$m(function (args) {
    var panel = args.panel;
    var menuEl = null;
    var boardMenu = null;
    var flowId = args.id;
    var isNew = args.idAdd;
    var callback = args.callback;
    var board = panel.flowpanel('getBoard');
    var parentId = board.attr('id');
    var logger = panel.flowpanel('getLogger');
    var that = this;
    //最后修改时间
    that.lastUpdateTime = null;
    that.parentId = null;

    //提示框高度
    var showTipHeight = 249;
    //提示框宽度
    var showTipWidth = 300;

    /**
     * 弹框提示
     * @param msg
     */
    var showTip = function (msg) {
        $("<div/>").alert({
            msg: msg,
            title: TempoUtils.locale("mine.prompt")
        });
    }


    var loadAnalyseFlow = function () {
        if (isNew) {
            renderBoard({});
            return;
        }
        if (!flowId) {
            console.warn('loadAnalyseFlow: undefined flowId')
            return;
        }
        var pro = $("<div/>").tempoprogressbar();
        $.ajax({
            url: contextPath + "/api/ai/resource/getResourceById",
            data: {
                id: flowId
            },
            type: 'post',
            dataType: 'json',
            success: function (rs) {
                var params = rs && rs.success ? rs.data : {};
                var a = new Date().getTime();
                //处理XML过大导致接口加载慢的问题，将XML在后端压缩后传递到前端在进行解压
                params.content = TempoMineUtils.unzip(params.content);
                var b = new Date().getTime();
                console.log("解压时长：" + (b - a) + "ms");
                renderBoard(params || {});
                that.lastUpdateTime = params.visitTime;
                that.parentId = params.parentId;
            },
            complete: function () {
                if (window.isFlowView) {
                    $(".tempo-mine-tabs").hide()
                }
                pro.tempoprogressbar("destroy");
            }
        });
    }

    /**
     * 渲染面板
     */
    var renderBoard = function (param) {
        var content = param.content || '{}';
        var boardData = JSON.parse(content);
        content = boardData.flow || {};
        content.name = param.name;
        content.runTimeConfig = boardData.runTimeConfig;
        content.flowParams = boardData.flowParams || content.flowParams;
        // 通过获取当前面板和board来渲染，否则恢复调用拿到panel和board不是自己的对象
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var id = analyseStatus.getMainId();
        analyseStatus.addMainData(id, param);
        var page = analyseStatus.getFlowPanel(id);
        var board = page.panel.flowpanel('getBoard');
        //初始化流程状态到panel，以便加载日志
        panel.flowpanel('updateFlowStatus', boardData.status);
        //初始化流程配置信息到面板
        panel.flowpanel('updateFlowRunTimeConfig', boardData.runTimeConfig);
        panel.flowpanel('updateFlowParams', content.flowParams);
        panel.flowpanel('updateMineServiceInfo', boardData.mineServiceInfo);
        panel.flowpanel('setExid', boardData.exid);
        panel.flowpanel('option', 'statusUpdateTag', boardData.statusUpdateTag);
        panel.flowpanel('option', 'insightControlInfo', boardData.insightControlInfo);
        //更新数据，importNotExecuted默认为false
        if (boardData && boardData.importNotExecuted) {
            panel.flowpanel('updateImportNotExecuted', boardData.importNotExecuted);
        }
        //更新数据，flowType默认为普通流程flow
        if (param && param.type) {
            panel.flowpanel('updateFlowType', param.type);
        }
        // 对数据的输入输出节点和模型相关节点做限制
        if (boardData.iscopy) {
            var mark = function (children) {
                for (var i in children) {
                    if (children[i].process && children[i].process.flow
                        && children[i].process.flow.children
                        && children[i].nodeType == 'subprocess') {
                        children[i]._forceConfirm = true;
                        mark(children[i].process.flow.children);
                    }
                }
            }
            mark(content.children || []);
        }
        var isEditable = true;
        if (window.apiPreview) {
            isEditable = false;
        }
        board.miningboard({
            canBeEdit: isEditable,
            data: content,
            filter: '.tempo-groupmenu-item-text',
            dropOptions: {
                accept: '.tempo-groupmenu-item-text',
                drop: boardDrop
            },
            renderChild: function (data, parent) {
                var style = data.style;
                renderNode(style,
                    data,
                    parent,
                    this.miningboard('getJspInstance'));

            }
        });
        panel.flowpanel('setNavigatorRoot');
        //初始化所有节点的位置
        board.miningboard("initSize");
        //更新执行节点的位置
        board.miningboard("updateSize");
        panel.flowpanel('setZoom', boardData.transform || '100');
        if (boardData.logger && boardData.logger.message) {
            panel.flowpanel('getLogger').flowlogger('showLog', boardData.logger.message, boardData.logger.messageTag);
        }
        //当正在运行时，则需继续请求日志
        if (!panel.flowpanel('isReady')) {
            panel.flowpanel('startStatusTimer', boardData.exid, boardData.mineServiceInfo, true);
        }
        board.unbind("contextmenu").bind("contextmenu", function (e) {
            //只有在特定的面板上才能右键菜单
            if (!window.apiPreview) {
                initBoardMenu(e, board);
            }
        });
        panel.flowpanel('loaded');
        Eventbus.one("model_library_renderNode.mine", renderNode);
        Eventbus.one("model_library_getAlias.mine", _getAlias);
        var runningNode = panel.find('a.tempo-mining-tool-execution-led.RUNNING');
        if (runningNode.length > 1 ||
            ((boardData.status == 'FAILED' || boardData.status == 'FINISHED') && runningNode.length > 0)) {
            var status = boardData.status == 'FAILED' ? 'FAILED' : boardData.status == 'FINISHED' ? 'SUCCESS' : 'READY';
            console.error('Find ', runningNode.length, 'running nodes');
            runningNode.parents('.tempo-miningnode').each(function () {
                var e = $(this);
                e[e.attr('_widgetname')]('updateExecStatus', status);
            });
        }
        //初始化洞察设置
        Eventbus.trigger("initinsight.mine")
        //清除面板属性，此属性只在初始化面板使用
        board.miningboard("emptyValidateNodeIsReady");
    }

    function _getAlias(config, board) {
        var flow = board.miningboard("getJson");
        var defaultName = config.name;
        var reg = new RegExp("^" + TempoMineUtils.flapRegex(config.name) + "(\\d*)$")
        var dss = flow.children;
        if (dss && dss.length > 0) {
            var index = -1;
            for (var i = 0; i < dss.length; i++) {
                var node = dss[i];
                var nodeLabel = node.alias ? node.alias : node.label;
                var match = reg.exec(nodeLabel);
                if (match && match.length > 1) {
                    if (match[1] == "") {
                        if (index < 0) {
                            index = 0;
                        }
                    } else {
                        index = Math.max(index, parseInt(match[1]));
                    }
                }
            }
            if (index > -1) {
                defaultName = defaultName + (index + 1);
            }
        }
        return defaultName;
    }

    var nodeLimit = function (panel, config) {
        if (config.id == "commentbox") {
            return false;
        }
        var processDepth = panel.flowpanel('getNavDepth');//获得层级深度
        //multiNodes下有prevObject指的是没有过滤掉的
        var multiNodes = panel.find('.tempo-miningnode').filter('[_widgetname="minemultiplynode"],[_widgetname!="minecommentnode"]')
        /**
         * 子流程最多限制一层
         */
        if (processDepth > 1) {
            var limits = ['subprocess', 'loopsampledata'];
            //'regressionBagging','bagging','regcrossvalidation', 'clacrossvalidation' 禁止bagging里再套bagging 在下面禁止
            if (limits.indexOf(config.id) > -1) {
                return true;
            }
        }
        /**
         * bagging、交叉验证分类算法:最多限制一层,bagging分类节点在拖入算法时只允许拖入分类算法且算法中
         * 不允许拖入自身,bagging分类节点通过配置参数按钮的id来判断进入的是否是bagging分类节点。
         */
        var classificationList = ['adaboost', 'xgboost'];
        if (processDepth > 1 && (panel.find("#bagging-parameters-btn").length > 0 ||
            panel.find(".clacrossvalidation-parameters").length > 0)) {
            if (config.type == 'datamine') {
                if (config.category == 'classification') {
                    //bagging节点子页面限制只能拖入一个算法节点。子页面div一定会有START和END,所以>2时，return true
                    if (multiNodes.length > 2) {
                        return true;
                    }
                    if (config.id == 'bagging' || config.id == 'clacrossvalidation') {//bagging节点不能拖入子页面
                        return true;
                    }
                    if (panel.find("#bagging-parameters-btn").length > 0 && config.id == 'knn') {
                        return true;
                    }
                    return false;
                } else {
                    return true;
                }
            } else if (classificationList.indexOf(config.id) > -1) {
                if (multiNodes.length > 2) {
                    return true;
                }
                return false;
            } else {
                return true;
            }
        }
        /**
         * bagging、交叉验证回归算法:最多限制一层,bagging回归节点节点在拖入算法时只允许拖入回归算法且算法中
         * 不允许拖入自身,bagging回归节点通过配置参数按钮的id来判断进入的是否是bagging回归节点。
         */
        var regressionList = [];
        if (processDepth > 1 && (panel.find("#regressionBagging-parameters-btn").length > 0 ||
            panel.find(".regcrossvalidation-parameters").length > 0)) {
            if (config.type == 'datamine') {
                if (config.category == 'regression') {
                    //节点子页面限制只能拖入一个算法节点。子页面div一定会有START和END,所以>2时，return true
                    if (multiNodes.length > 2) {
                        return true;
                    }
                    if (config.id == 'regressionBagging' || config.id == 'regcrossvalidation') {
                        return true;
                    }
                    return false;
                } else {
                    return true;
                }
            } else if (regressionList.indexOf(config.id) > -1) {
                if (multiNodes.length > 2) {
                    return true;
                }
                return false;
            } else {
                return true;
            }
        }
        /**
         * 自动择参
         */
        if (processDepth > 1 && panel.find(".parameterselect-parameters").length > 0) {
            if (config.type == 'datamine') {
                if (config.category == 'regression' || config.category == 'classification' || config.category == 'clustering' || config.category == 'timeseries') {
                    if (multiNodes.length > 2 || config.id == 'regressionBagging'
                        || config.id == 'bagging' || config.id == 'regressiondnn'
                        || config.id == 'classificationdnn' || config.id == 'lda'
                        || config.id == 'isotonicregression' || config.id == 'lstm'
                        || config.id == 'twostep'
                        || config.id == 'vectorautoreg' || config.id == 'x11'
                        || config.id == 'x12' || config.id == 'gray' || config.id == 'curveregression') {
                        return true;
                    }
                    return false;
                }
                return true;
            } else {
                return true;
            }
        }

        /**
         * 循环行节点
         */
        if (processDepth > 1 && panel.find(".loopsampledata-parameters").length > 0) {
            //不支持的节点id
            var notSupportNodeIds = ['automl', 'autoreg', 'autotimeseries', 'autoclustering', 'autoclassification', 'loopsampledata', 'subprocess', 'bagging', 'regressionBagging', 'autoclassification', 'parameterselect', 'regcrossvalidation', 'clacrossvalidation', 'pyspark', 'readpmmlmodel', 'pmmlapplymodel', 'syncoutput','tensorflow'];
            //不支持的二级分类'data_input'
            var notSupportCategory = [];
            //不支持的类型
            // var notSupportTypes = [window.constant.DATAMINE_SIGNAL];
            var notSupportTypes = [];
            var type = config.type;
            var id = config.id;
            var category = config.category;
            if (notSupportTypes.indexOf(type) > -1 || notSupportCategory.indexOf(category) > -1 || notSupportNodeIds.indexOf(id) > -1 || ("user_defined" == category && ("tensorflow" == config.lang || "pyspark" == config.lang))) {
                return true;
            } else {
                return false;
            }
        }

        /**
         * 子流程节点
         */
        if (processDepth > 1 && panel.find(".subprocess-parameters").length > 0) {
            //不支持的二级分类
            var notSupportCategory = ['data_input'];
            //不支持节点
            var notSupportNodeIds = ['readpmmlmodel', 'pmmlapplymodel', 'syncoutput'];
            //不支持的类型
            var notSupportTypes = [window.constant.DATAMINE_SIGNAL];
            var id = config.id;
            var type = config.type;
            var category = config.category;
            var id = config.id;
            if (TempoMineUtils.classSubProcessArray.indexOf(id) > -1
                || notSupportTypes.indexOf(type) > -1
                || notSupportCategory.indexOf(category) > -1
                || notSupportNodeIds.indexOf(id) > -1) {
                return true;
            } else {
                return false;
            }
        }

        /**
         * 同步输入和同步输出节点只允许在第一层拖放,且只能拖放一个
         */
        if ((config.id == 'readsync' || config.id == 'syncoutput') && processDepth > 1) {
            return true;
        }
        if (config.id == 'readsync') {
            var multiNodes = panel.find('.tempo-miningnode')
                .filter(function (i, e) {
                    var data = $(e)[$(e).attr('_widgetname')]('getData');
                    return data.nodeType == config.id;
                });
            if (multiNodes && multiNodes.length > 0) {
                return true;
            }
        }
        //管道流程不支持多个同步输出接入
        //获取当前流程类型
        var flowType = Eventbus.triggerHandler("getFlowType.mine")[0];
        if (config.id == 'syncoutput' && flowType == "plflow") {
            var multiNodes = panel.find('.tempo-miningnode')
                .filter(function (i, e) {
                    var data = $(e)[$(e).attr('_widgetname')]('getData');
                    return data.nodeType == config.id;
                });
            if (multiNodes && multiNodes.length > 0) {
                return true;
            }
        }
        return false;
    }
    /**
     * 处理节点拖到面板后的事件
     */
    var boardDrop = function (evt, ui) {
        //api主题预览模式下,不进行操作
        if (window.apiPreview) {
            return false;
        }
        var config = ui.draggable.parents('div.tempo-groupmenu-item').data('data');
        var flowId = "#fc-" + TempoMineUtils.analyseStatus.getMainId();
        var boardDiv = $(flowId);
        var subprocessChildNode = boardDiv.find('.navigator-path-symble');
        if (config.name == undefined || ("pmml" == config.type && subprocessChildNode.length != 0)) {
            return;
        }
        var opts = {};
        var alias = "";
        if (typeof (config.libraryType) != "undefined" && config.libraryType == "modelLibray") {
            var modelName = config.name;
            //把name进行转移
            modelName = TempoMineUtils.decodeHTML(modelName)
            if (modelName.length > 30) {
                modelName = modelName.substring(0, 30);
            }
            if ("pmml" == config.type) {
                //alias = _getAlias({name: "PMML"+TempoUtils.locale("mine.readmodel"), id: "readpmmlmodel"}, board);
                //现在改为节点名称显示为模型名称 重复加1
                alias = _getAlias({name: modelName, id: "readpmmlmodel"}, board);
                opts = {category: "model_io", type: "dm_model", nodeType: "readpmmlmodel", alias: alias};
            } else {
                //alias = _getAlias({name: TempoUtils.locale("mine.readmodel"), id: "readmodel"}, board);
                alias = _getAlias({name: modelName, id: "readmodel"}, board);
                opts = {category: "model_io", type: "dm_model", nodeType: "readmodel", alias: alias};
            }

            var modelInfo = config.modelInfo;
            var modelInfoJSON = JSON.parse(modelInfo);
            var producerNodeTypeId = modelInfoJSON.producerNodeTypeId;
            if ("woe" == producerNodeTypeId) {
                $("<div/>").alert({
                    msg: TempoUtils.locale("mine.woeerror"),
                    height: 180
                });
                return false;
            }
            var modelSaveRootPath = modelInfoJSON.modelSaveRootPath;
            var description = config.description;
            var descArr = [];
            if (description == null || $.trim(description).length == 0) {
                if ($.isArray(modelInfoJSON.description)) {
                    descArr = modelInfoJSON.description;
                } else {
                    descArr = JSON.parse(modelInfoJSON.description);
                }
            } else {
                descArr = JSON.parse(config.description);
            }

            var metadataArr = [];
            if (descArr.length >= 3) {
                var metadataObjs = descArr[2];
                //处理导入导出pmml模型优化后，鼠标悬浮至模型库名称上不显示自变量、因变量的问题
                if ("string" === typeof (metadataObjs)) {
                    try {
                        metadataObjs = JSON.parse(metadataObjs);
                    } catch (e) {
                        console.log("JSON转化异常")
                    }
                }
                if (metadataObjs && metadataObjs.length && metadataObjs.length > 0) {
                    for (var i = 0; i < metadataObjs.length; i++) {
                        metadataArr.push(TempoMineMetaUtils.convertObjToMeta(metadataObjs[i]));
                    }
                }
            }
            var parameters = opts.parameters || {};
            parameters.isConfigredOk = true;
            parameters.modelSaveRootPath = modelSaveRootPath;
            parameters.metadata = metadataArr;
            //处理通过模型库添加进来的模型校验报错的问题
            parameters.uniqueId = config.id;
            parameters.producerNodeTypeId = producerNodeTypeId;
            if (modelInfoJSON && modelInfoJSON.insightInfo) {
                parameters.algoType = modelInfoJSON.insightInfo.algoType;
                if (modelInfoJSON.insightInfo.output && modelInfoJSON.insightInfo.output.length > 0) {
                    parameters.modelVersion = "1";
                    parameters.probOutPut = modelInfoJSON.insightInfo.output
                }
            }
            if ("pmml" != config.type) {
                // 增加版本信息
                parameters.modelName = config.name;
                parameters.modelVersion = config.version  ? config.version : config.createTime;
                parameters.modelNameUniqueCode = config.modelNameUniqueCode;
            }
            opts.parameters = parameters;
        } else {
            var alias = _getAlias(config, board);
            opts = {
                category: config.category,
                type: config.type,
                nodeType: config.id,
                alias: alias
            };
        }
        if (nodeLimit(panel, config)) return;

        var offset = this.miningboard('getContainer').offset();
        var left = evt.pageX - offset.left - 30;
        var top = evt.pageY - offset.top - 20;
        //子流程中拖拽节点遮挡左边竖条处理
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var id = analyseStatus.getMainId();
        var page = analyseStatus.getFlowPanel(id);
        if (page.panel.flowpanel('getNavDepth') > 1) {
            left < 30 && (left = 30);
            top < 20 && (top = 20);
        } else {
            left < 0 && (left = 0);
            top < 0 && (top = 0);
        }
        Eventbus.trigger("mining_board_change.mine");
        opts.droptime = new Date().getTime();//加入拖拽时间，用于方便新旧节点的区分
        var container = this.miningboard('getContainer');
        var plumbInstance = this.miningboard('getJspInstance');
        var node = renderNode({left: left, top: top},
            opts, container, plumbInstance);

        //拖拽节点后对特殊节点端口做特殊处理
        changeNodeScopes(panel, node, opts);

        if (node) {
            var widgetName = node.attr('_widgetname');
            var id = node.attr('id');
            var data = node[widgetName]('option', 'data');
            data = $.extend({}, opts);
            var $this = this;
            var undoManager = analyseStatus.getUndoManager();
            undoManager.add({
                undo: function () {
                    console.log("回退节点拖到面板");
                    var node = $('#' + parentId).find('#' + id);
                    var widgetName = node.attr('_widgetname');
                    data = node[widgetName]('option', 'data');
                    if (node && widgetName) {
                        node[widgetName]('remove');
                    }
                    Eventbus.trigger("mining_board_change.mine");
                },
                redo: function () {
                    var board = $('#' + parentId);
                    renderNode({left: left, top: top}, data,
                        board.miningboard('getContainer'),
                        board.miningboard('getJspInstance'));
                    Eventbus.trigger("mining_board_change.mine");
                }
            });
            //拖拽节点时触发，判断撤销和重做是否变黑
            Eventbus.trigger('enableUndoRedoButton.mineToolbar')
        }
    }

    /**
     * 拖拽节点后对特殊节点端口做特殊处理
     * @param panel 面板
     * @param node 节点Dom元素
     * @param opts 节点信息
     */
    var changeNodeScopes = function (panel, node, opts) {
        //获得层级深度
        var processDepth = panel.flowpanel('getNavDepth');
        //当前面板为自动择参
        if (processDepth > 1 && panel.find(".parameterselect-parameters").length > 0 && opts.nodeType == "knn") {
            var outScopes = node[node.attr("_widgetName")]('option', 'data').scope.outScope;
            //自动择参内部拖拽knn节点删除knn近邻集端口
            node[node.attr("_widgetName")]("removeScope", outScopes[outScopes.length - 1], "out");
        }
    }

    /**
     * 渲染节点
     */
    var renderNode = function (style, opts, container, jspInstance) {
        //如果节点的位置left小于30，则给30
        if (!window["preEditStatus"] && opts.style && opts.style.left < 30) {
            opts.style.left = 30;
        }
        var yarnMasterNodes = ["writehive", "readhive", 'tensorflow', 'readhbase', 'writehbase', 'readhdfs', 'writehdfs'];
        /*if (window["TempoMineServerMasterType"] && window["TempoMineServerMasterType"]["tempoMineServerMasterType"] != "yarn-cluster" ) {
			if (opts.nodeType && yarnMasterNodes.indexOf(opts.nodeType) != -1) {
				return;
			}
		}*/
        if (!style || !opts.nodeType) return;
        if (opts.nodeType != "commentbox") {
            delete style.width;
        }
        var div = $("<div/>").css(style);
        container.append(div);
        if (!window[opts.type]) {
            return;
        }
        var config = window[opts.type][opts.nodeType];
        config = config || window[window.constant.MNODES][opts.nodeType];
        if (!config) {
            console.error("要加载的节点不存在，请检查");
            return;
        }
        var rendernode = config.renderNode;
        //将entry 输入接口参数传入到节点
        opts.entry = config.entry;
        opts.imitatesub = config.imitatesub;
        opts.aicategory = config.aicategory;
        rendernode = rendernode && rendernode != "" ? rendernode : "miningnode";

        var canBeEdit = true;
        var draggable = true;
        if (window.apiPreview) {
            canBeEdit = false;
            draggable = false;
        }
        //渲染节点做特殊处理
        opts = updateNodeScopes(opts);
        var node = div[rendernode]($.extend(true, {}, {
            showHandle: false,
            canBeEdit: canBeEdit,
            draggable: draggable,
            data: opts,
            loadProp: true,
            containment: container,
            jspInstance: jspInstance,
            enableValidate: container.parent().miningboard('isAutoValidateNode'),
            board: container.parent(),
            click: function (e) {
                var config = window[window.constant.MNODES][$(this)[rendernode]('option').data.nodeType];
                $('#tempo-mine-element-library').elementlibrary('showHelp', config);
            }
        }));
        div.unbind("contextmenu").bind("contextmenu", function (e) {
            if (!window.apiPreview) {
                initMenu(e, div);
            }
            e.preventDefault();
            e.stopPropagation();
        });
        return node;
    }

    /**
     * 特殊节点更新端口(不知道为什么文件输出节点会出现输入端口和输出端口一样的情况，在渲染的时候)
     * @param opts
     */
    var updateNodeScopes = function (opts) {
        //如果渲染的节点类型为文件输出类型
        if (opts.nodeType == "writefile" || opts.nodeType == "writefilebatch") {
            if (opts.scope) {
                var outScope = opts.scope.outScope;
                var inScope = opts.scope.inScope;
                if (outScope.length == inScope.length) {
                    var newOutScope = [];
                    var codeList = [];
                    for (var i = 0; i < outScope.length; i++) {
                        if (codeList.indexOf(outScope[i].code) == -1) {
                            newOutScope.push(outScope[i]);
                            codeList.push(outScope[i].code);
                        }
                    }
                    opts.scope.outScope = newOutScope;
                }
            }
        }
        return opts;
    }

    function initMenu(e, o) {
        var data = o[o.attr('_widgetname')]('getData');
        console.log(data._widgetName);
        //获取到是隐藏注释还是显示注释
        var board = $('#' + parentId);
        var flow = board.miningboard("getJson");
        var comsflag = flow.comsflag;

        //当前节点如果没有被选中，则清除掉所有的选中信息
        if (!($(o).hasClass("tempo-basenode-select") || $(o).hasClass("tempo-minecommentnode-select"))) {
            var selList = board.find(".tempo-basenode").not("#END", "#START") || [];
            var selListLength = selList.length;
            for (var i = 0; i < selListLength; i++) {
                var targetNode = $(selList[i]);
                targetNode[targetNode.attr("_widgetname")]("unselectNodeByMouse");
            }
        }

        //屏蔽掉注释节点的右键菜单
        if (!TempoUtils.equals(data._widgetName, "minecommentnode")) {
            var isSupportCache = o[o.attr('_widgetname')]('isSupportCache');
            var isSubprocessInternalNode = o[o.attr('_widgetname')]('isSubprocessInternalNode');
            //是否是循环行内部节点
            // var isLoopsampledataInternalNode = false;
            // if (board.parent().length > 0 && board.parent().parent().length > 0 && board.parent().parent().find("span.loopsampledata-parameters").length > 0) {
            //     isLoopsampledataInternalNode = true;
            // }

            var isStartNextNodeExcute = o[o.attr('_widgetname')]('isStartNextNodeExcute');
            var isEndNode = o[o.attr('_widgetname')]('isEndNode');
            var iscache = data.parameters.iscachesucess;
            var cachestatus = data.parameters.cachestatus;
            //获取当前流程类型
            var flowType = Eventbus.triggerHandler("getFlowType.mine")[0];
            var contextmenuData = [
                {
                    text: TempoUtils.locale("mine.mine_rename"),
                    icon: 'ui-icon tempo-ui-icon tempo-ui-icon-rename',
                    id: 'RENAME',
                    disabled: false
                },
                {
                    text: TempoUtils.locale("mine.mine_del"),
                    icon: 'ui-icon tempo-ui-icon tempo-ui-icon-delete',
                    id: 'DEL',
                    disabled: false
                },
                {
                    text: TempoUtils.locale("mine.mine_copy"),
                    icon: 'ui-icon tempo-ui-icon tempo-ui-icon-copy',
                    id: 'COPY',
                    disabled: false
                },
                {
                    text: TempoUtils.locale("mine.mine_pointnote"),
                    icon: 'ui-icon tempo-ui-icon tempo-ui-icon-pointnote',
                    id: 'POINTNOTE',
                    disabled: false
                }
            ];
            if (!comsflag) {
                contextmenuData[3].disabled = true;
            }
            if (isSupportCache) {
                if (!isSubprocessInternalNode) {
                    contextmenuData = [
                        {
                            text: TempoUtils.locale("mine.mine_rename"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-rename',
                            id: 'RENAME',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.mine_del"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-delete',
                            id: 'DEL',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.mine_copy"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-copy',
                            id: 'COPY',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.mine_pointnote"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-pointnote',
                            id: 'POINTNOTE',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.open_cache"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-opencache',
                            id: 'OPENCACHE',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.close_cache"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-closecache',
                            id: 'CLOSECACHE',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.delete_cache"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-deletecache',
                            id: 'DELETECACHE',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.endbreakpoint"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-endbreakpoint',
                            id: 'ENDBREAKPOINT',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.startbreakpoint"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-startbreakpoint',
                            id: 'SATRTBREAKPOINT',
                            disabled: false
                        }
                    ];
                    if (!comsflag) {
                        contextmenuData[3].disabled = true;
                    }
                    //仅IotDB输出节点支持图表分析菜单
                    if (data.nodeType && data.nodeType == "writeiotdb") {
                        var iotdbContextmenuData = {
                            text: "图表分析",
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-multiline',
                            id: 'GRAPH',
                            disabled: false
                        };
                        contextmenuData.push(iotdbContextmenuData);
                        if (o.find(".SUCCESS").length == 0) {
                            contextmenuData[9].disabled = true;
                        }
                    }
                    if (cachestatus == window.constant.OPENCACHE) {
                        contextmenuData[4].disabled = true;
                        contextmenuData[5].disabled = false;
                        contextmenuData[6].disabled = false;
                    } else if (cachestatus == window.constant.CLOSECACHE) {
                        contextmenuData[4].disabled = false;
                        contextmenuData[5].disabled = true;
                        contextmenuData[6].disabled = true;
                    } else if (cachestatus == window.constant.DELETECACHE) {
                        contextmenuData[4].disabled = true;
                        contextmenuData[5].disabled = false;
                        contextmenuData[6].disabled = true;
                    }
                    contextmenuData[6].disabled = !iscache;
                    contextmenuData[8].disabled = !isStartNextNodeExcute;
                    if (isEndNode) {
                        contextmenuData[8].disabled = true;
                    }
                    //当前面板流程类型为管道流程，禁用缓存功能和从下一个节点开始执行功能
                    if (flowType == "plflow") {
                        contextmenuData[4].disabled = true;
                        contextmenuData[5].disabled = true;
                        contextmenuData[6].disabled = true;
                        contextmenuData[8].disabled = true;
                    }
                } else {
                    contextmenuData = [
                        {
                            text: TempoUtils.locale("mine.mine_rename"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-rename',
                            id: 'RENAME',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.mine_del"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-delete',
                            id: 'DEL',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.mine_copy"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-copy',
                            id: 'COPY',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.mine_pointnote"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-pointnote',
                            id: 'POINTNOTE',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.open_cache"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-opencache',
                            id: 'OPENCACHE',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.close_cache"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-closecache',
                            id: 'CLOSECACHE',
                            disabled: false
                        },
                        {
                            text: TempoUtils.locale("mine.delete_cache"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-deletecache',
                            id: 'DELETECACHE',
                            disabled: false
                        }
                    ];
                    if (!comsflag) {
                        contextmenuData[3].disabled = true;
                    }
                    if (cachestatus == window.constant.OPENCACHE) {
                        contextmenuData[4].disabled = true;
                        contextmenuData[5].disabled = false;
                        contextmenuData[6].disabled = false;
                    } else if (cachestatus == window.constant.CLOSECACHE) {
                        contextmenuData[4].disabled = false;
                        contextmenuData[5].disabled = true;
                        contextmenuData[6].disabled = true;
                    } else if (cachestatus == window.constant.DELETECACHE) {
                        contextmenuData[4].disabled = true;
                        contextmenuData[5].disabled = false;
                        contextmenuData[6].disabled = true;
                    }
                    contextmenuData[6].disabled = !iscache;
                    //循环行内部不能开启缓存
                    if (isSubprocessInternalNode) {
                        contextmenuData.splice(4, 3)
                    }
                }

            }

            // 获取是否开启了代码转自定义算法
            var codeTransformAlgorithm = false;
            $.ajax({
                url: contextPath + "/api/ai/mine/get-code-transform-algorithm",
                type: 'get',
                async: false,
                success: function (res) {
                    codeTransformAlgorithm = res.data;
                }
            });
            //为python扩展编程添加代码转自定义算法
            // 标识发布为自定义算子选项和算子列表选项是否可用
            if (data.nodeType && data.nodeType == "pythonscript" && codeTransformAlgorithm) {
                // 标识发布为自定义算法是否置灰
                var publishUdfAlgDisabledTmp = true;
                if (data.status == "SUCCESS" && data.parameters.tempoAICustomAlg && data.parameters.tempoAICustomAlg.openCodeTransformUdf) {
                    publishUdfAlgDisabledTmp = false;
                }
                // 添加发布为自定义算子选项
                contextmenuData.push({
                    text: TempoUtils.locale("mine.publish_custom_alg"),
                    icon: 'tempo-ui-icon-publish-custom-alg',
                    id: 'PUBLISHCUSTOMALG',
                    disabled: publishUdfAlgDisabledTmp
                });
                // 添加算子列表选项
                contextmenuData.push({
                    text: TempoUtils.locale("mine.custom_alg_list"),
                    icon: 'tempo-ui-icon-custom-alg-list',
                    id: 'CUSTOMALGLIST',
                    disabled: false
                });

                // 将python的端口信息更新到tempoAICustomAlg里
                if (data.parameters.tempoAICustomAlg && data.parameters.tempoAICustomAlg.designModel) {
                    data.parameters.tempoAICustomAlg.designModel.scopes = TempoUtils.clone(data.scope);
                    data.parameters.tempoAICustomAlg.isConnectModel = false;
                    // 判断python节点是否连接N端口，获取输入输出的最后一条线的值
                    // 获取所有连线信息，查找python节点是否连接了N端口
                    var connectLineAll = o[o.attr('_widgetname')]('option').jspInstance.getConnections();
                    var connectLineAllLen = connectLineAll.length;
                    for (var i = 0; i < connectLineAllLen; i++) {
                        var portUuidsArray = connectLineAll[i].getUuids();
                        if (portUuidsArray.indexOf(data.eid + "_in_object") != -1 ||
                            portUuidsArray.indexOf(data.eid + "_out_object") != -1) {
                            data.parameters.tempoAICustomAlg.isConnectModel = true;
                            break;
                        }
                    }
                }
            }

            // 如果选择的节点数目大于1 那么开启批量菜单
            var tag = 0;
            var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
            var boardId = analyseStatus.getMainId();
            var panel = analyseStatus.getFlowPanel(boardId).panel;
            var board = panel.flowpanel('getBoard');
            var nodeArray = board.find(".tempo-basenode[id!='END']");
            $.each(nodeArray, function (i, v) {
                if (v.className.indexOf("tempo-basenode-select") != -1 || v.className.indexOf("tempo-minecommentnode-select") != -1) {
                    tag++;
                }
            });
            if (tag > 1) {
                contextmenuData = [
                    {
                        text: TempoUtils.locale("mine.mine_copy"),
                        icon: 'ui-icon tempo-ui-icon tempo-ui-icon-copy',
                        id: 'BATCHCOPY',
                        disabled: false
                    },
                    {
                        text: TempoUtils.locale("mine.mine_del"),
                        icon: 'ui-icon tempo-ui-icon tempo-ui-icon-delete',
                        id: 'BACTCHDEL',
                        disabled: false
                    }
                ];
            }

            var tag = $(e.target).parents('.tempo-mine-flow-container').flowpanel('isRunning');
            if (tag == true) {
                var retainIndex = ["BATCHCOPY", "COPY"];
                contextmenuData.forEach(function (v, i) {
                    if (retainIndex.indexOf(v.id) == -1) {
                        v.disabled = true;
                    }
                })
            }
            //如果有miningboardnodepro-menu，先移除掉该dom
            var menu = $('ul.miningboardnodepro-menu');
            if (!menu.length) {
                menu.remove();
            }
            menuEl = $("<ul/>").addClass("miningboardnodepro-menu").contextmenu({
                data: contextmenuData,
                showTitle: true,
                select: function (e, ui) {
                    e.stopPropagation();
                    selectMenu(e, ui);
                },
                close: function () {
                    menuEl.contextmenu("enableAll").contextmenu("collapseAll");
                }
            }).appendTo($("body"));
            menuEl.bind("contextmenu", function (e) {
                e.preventDefault();
            });
            //菜单宽度默认为165
            var menuElWidth = 165;
            //菜单高度和菜单数量有关
            var menuElHeight = 30 * contextmenuData.length;
            if (isSupportCache) {
                menuEl.width(menuElWidth);
            }
            var config = o[o.attr('_widgetname')]('getConfig');
            var blacklist = []; //'readdatabank'
            if (blacklist.indexOf(config.id) > -1) {
                menuEl.contextmenu("hideItem", "COPY");
            } else {
                menuEl.contextmenu("showItem", "COPY");
            }
            //矫正菜单显示位置，处理不同分辨率下菜单显示不全问题
            var screenWidth = window.screen.width;
            //减去143是浏览器上边的高度
            var screenHeight = window.screen.height - 143;
            var menuElLeft = e.pageX;
            var menuElTop = e.pageY;
            if ((e.pageX + menuElWidth) > screenWidth) {
                menuElLeft = e.pageX - menuElWidth;
            }
            if ((e.pageY + menuElHeight) > screenHeight) {
                menuElTop = e.pageY - menuElHeight;
            }
            //显示菜单
            menuEl.contextmenu("show", {
                linkEl: o,
                position: {
                    left: menuElLeft,
                    top: menuElTop
                }
            })
            e.preventDefault();
        }
    }

    function selectMenu(e, ui) {
        console.log("right click");
        if (ui.select.id == "DEL") {
            var tt = $(ui.linkEl);
            var opts = board.miningboard('deleteNode', tt);

            var undoManager = analyseStatus.getUndoManager();
            undoManager.add({
                undo: function () {
                    console.log("回退删除节点");
                    var board = $('#' + parentId);
                    board.miningboard('drawNode', opts);
                    Eventbus.trigger("mining_board_change.mine");
                },
                redo: function () {
                    var board = $('#' + parentId);
                    var node = board.find('#' + opts.data.eid);
                    var widgetName = node.attr('_widgetname');
                    if (node && widgetName) {
                        opts = board.miningboard('deleteNode', node);
                    }
                    Eventbus.trigger("mining_board_change.mine");
                }
            });
            //删除节点时触发，判断撤销和重做是否变黑
            Eventbus.trigger('enableUndoRedoButton.mineToolbar');
            Eventbus.trigger("mining_board_change.mine");
        } else if (ui.select.id == "COPY") {
            copyNode(ui.linkEl);
        } else if (ui.select.id == "RENAME") {
            var tt = $(ui.linkEl);
            tt[tt.attr("_widgetName")]("renameNode");
        } else if (ui.select.id == "POINTNOTE") {
            var tt = $(ui.linkEl);
            tt[tt.attr("_widgetName")]("addpointnote", e, ui);
        } else if (ui.select.id == "OPENCACHE") {
            var tt = $(ui.linkEl);
            tt[tt.attr("_widgetName")]("openCache");
        } else if (ui.select.id == "CLOSECACHE") {
            var tt = $(ui.linkEl);
            tt[tt.attr("_widgetName")]("closeCache", true);
            //mineSave();
        } else if (ui.select.id == "DELETECACHE") {
            var tt = $(ui.linkEl);
            tt[tt.attr("_widgetName")]("deleteCache");
            //mineSave();
        } else if (ui.select.id == "ENDBREAKPOINT") {
            var node = $(ui.linkEl);
            var run = {
                type: "runto",
                data: node
            }
            mineSave(run);
            //runToCurrentNode(node);
        } else if (ui.select.id == "SATRTBREAKPOINT") {
            var node = $(ui.linkEl);
            var run = {
                type: "start",
                data: node
            }
            mineSave(run);
            //startRunCurrentNode(node);
        } else if (ui.select.id == "BATCHCOPY") {
            copyNodeBatch(ui.linkEl);
        } else if (ui.select.id == "BACTCHDEL") {
            batchDeleteNode(e, ui);
        } else if (ui.select.id == "GRAPH") {
            graphDialog("GRAPH", $(ui.linkEl));
        } else if (ui.select.id == "PUBLISHCUSTOMALG") {
            publishCustomAlg(e, ui);
        } else if (ui.select.id == "CUSTOMALGLIST") {
            customAlgList(e, ui);
        }
        e.preventDefault();
    }


    /**
     * 赋值节点信息，放置到公共区域
     */
    var copyNode = function (ele) {
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        analyseStatus.put('copyNodeList', []);
        analyseStatus.put('copyNodeConnections', []);
        var node = $(ele);
        var config = node[node.attr('_widgetname')]('getConfig');
        var data = node[node.attr('_widgetname')]('getData');
        var cloneData = TempoUtils.clone(data);
        var parameters = cloneData.parameters || {};
        parameters.cachestatus = window.constant.CLOSECACHE;
        parameters.iscachesucess = false;
        var copy = {config: config, data: cloneData, x: node[0].offsetLeft, y: node[0].offsetTop};
        analyseStatus.put('copyNodeList', [copy]);
    }
    /**
     * 批量复制当前的选择的节点，放置到公共区域
     */
    var copyNodeBatch = function () {
        var progressbar = $("<div/>").tempoprogressbar();
        setTimeout(function () {
            var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
            analyseStatus.put('copyNodeList', []);
            analyseStatus.put('copyNodeConnections', []);
            var boardId = analyseStatus.getMainId();
            var panel = analyseStatus.getFlowPanel(boardId).panel;
            var board = panel.flowpanel('getBoard');
            var nodeArray = board.find(".tempo-basenode").not("#END", "#START");
            var copyList = [];

            var nodeIdArray = [];
            $.each(nodeArray, function (i, nodeTemp) {
                var node = $(nodeTemp);
                if (node.css("display") !== "none" && (node.hasClass("tempo-basenode-select") == true || node.hasClass("tempo-minecommentnode-select") == true)) {
                    nodeIdArray.push(node.attr("id"));
                    var config = node[node.attr('_widgetname')]('getConfig');
                    var data = node[node.attr('_widgetname')]('getData');
                    var cloneData = TempoUtils.clone(data);
                    var parameters = cloneData.parameters || {};
                    parameters.cachestatus = window.constant.CLOSECACHE;
                    parameters.iscachesucess = false;
                    var copy = {config: config, data: cloneData, x: node[0].offsetLeft, y: node[0].offsetTop};
                    copyList.push(copy);
                }
            });

            //获取连线信息
            var plumbInstance = board.miningboard('getJspInstance');
            var allConnections = plumbInstance.getAllConnections();
            var targetConnections = [];
            $.each(allConnections, function (i, item) {
                var sourceId = item.sourceId;
                var targetId = item.targetId;
                var sourceIdIndex = nodeIdArray.indexOf(sourceId);
                var targetIdIndex = nodeIdArray.indexOf(targetId);
                if (sourceIdIndex > -1 && targetIdIndex > -1) {
                    targetConnections.push(item.getUuids());
                    //给copyList中下标为sourceIdIndex和targetIdIndex的节点添加不能删除端口属性
                    copyList[sourceIdIndex]["data"]["disableDeleteScope"] = true;
                    copyList[targetIdIndex]["data"]["disableDeleteScope"] = true;
                }
            });
            //对copyList进行排序，注释节点在前
            var targetCopyList = [];
            var copyListLength = copyList.length;
            for (var i = 0; i < copyListLength; i++) {
                if (copyList[i].data.nodeType === "commentbox") {
                    targetCopyList.push(copyList[i])
                }
            }
            for (var i = 0; i < copyListLength; i++) {
                if (copyList[i].data.nodeType !== "commentbox") {
                    targetCopyList.push(copyList[i])
                }
            }

            analyseStatus.put('copyNodeList', targetCopyList);
            analyseStatus.put('copyNodeConnections', targetConnections);

            progressbar.tempoprogressbar("destroy");
        }, 10);
    }
    /**
     * 遮罩管理
     * */
    var Mask = (function () {
        var map = {};
        return {
            create: function (param) {
                param = param || {};
                var p = $("<div/>").tempoprogressbar(param).uniqueId();
                var id = p.attr('id');
                map[id] = new Date().getTime();
                return p;
            },
            hide: function (pro) {
                if (pro) {
                    var id = pro.attr('id');
                    var t = map[id];
                    delete map[id];
                    var e = new Date().getTime();
                    var delay = e - t < 300 ? 300 : 1;
                    setTimeout(function () {
                        pro.tempoprogressbar("close");
                    }, delay);
                }
            }
        }
    })();
    var getNewPageData = function () {
        return {
            id: TempoUtils.uuid(),
            name: null,
            type: 'flow',
            appId: window[constant.APP_ID],
            parentId: that.parentId,
            sort: 0
        }
    }
    var saveSceneStrategy = {
        "cover": function (content, id, e) {
            $.ajax({
                url: contextPath + '/api/ai/resource/save',
                data: {
                    id: id,
                    content: content,
                    lastUpdateTime: ""
                },
                dataType: 'json',
                type: 'post',
                success: function (result) {
                    //如果不是手动保存，则不需要进行提示
                    //不提示保存成功
                    if (result.success) {
                        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
                        analyseStatus.addMainData(id, result.data);
                        Eventbus.trigger("mining_board_save.mine", id);
                        if (e == true) {
                            var page = analyseStatus.getFlowPanel(id);
                            if (!page.panel.flowpanel('isReady')) {
                                $("<div/>").alert({
                                    msg: TempoUtils.locale("mine.taskRunningError"),
                                    title: TempoUtils.locale("mine.runtask")
                                });
                                return;
                            }
                            Eventbus.trigger('startupFromBar.mine');
                        } else if (e && e.type == "runto") {
                            runToCurrentNode(e.data);
                        } else if (e && e.type == "start") {
                            startRunCurrentNode(e.data);
                        }
                    }
                },
                error: function (response) {
                    var message = TempoUtils.locale("mine.saveFailed");
                    if (response.getResponseHeader("Merit-Session-Expired") == "true") {
                        message = TempoUtils.locale("mine.sessionTimeout");
                    }
                    $("<div/>").alert({
                        msg: message,
                        title: document.title
                    });
                }
            });
        },
        "saveAs": function (content, id, e) {
            //Mask.create();
            var item = getNewPageData();
            item.copyId = id;
            Eventbus.trigger("mine.saveAs", item, content, e);
            //Mask.hide();
        },
        "leave": function (data, id, e) {
            var board = $('#md-' + id);
            board.miningboard("destroy");
            renderBoard(data.content);
            Eventbus.trigger("mining_board_save.mine", id);
            // if(!e){
            // 	var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
            // 	var id = analyseStatus.getMainId();
            // 	var page = analyseStatus.getFlowPanel(id);
            // 	if(!page.panel.flowpanel('isReady')){
            // 		$("<div/>").alert({
            // 			msg: TempoUtils.locale("mine.taskRunningError"),
            // 			title: TempoUtils.locale("mine.runtask")
            // 		});
            // 		return;
            // 	}
            // 	Eventbus.trigger('startupFromBar.mine');
            // }
        }
    }

    /**
     * 多人编辑
     */
    var selectSaveStrategy = function (res, scene, id, e) {
        var div = $("<div/>").dialog(
            {
                width: 230,
                height: 300,
                modal: true,
                open: function () {
                    var msg = TempoUtils.locale(
                        "mine.mine_msg_curpage_editor").replace("XXXXX",
                        res.username);
                    $("<p style='text-align:center;margin-top:20px;'>" + msg + "</p>")
                        .appendTo($(this));
                    $('<div class="ui-dialog-buttonset" style="\n' +
                        '    text-align: center;\n' +
                        '    position: absolute;\n' +
                        '    top: 100px;\n' +
                        '    left: 0;\n' +
                        '"><button type="button" id="saveAs" class="tempo-button ui-button ui-corner-all ui-widget" ' +
                        'style="height: 28px;line-height: 26px;width: 120px;padding: 0px;margin: 5px 0px;"' +
                        '>' + TempoUtils.locale("mine.base_saveas") + '</button>' +
                        '<button type="button" id="cover" class="tempo-button ui-button ui-corner-all ui-widget" ' +
                        'style="height: 28px;line-height: 26px;width: 120px;padding: 0px;margin: 5px 0px;"' +
                        '>' + TempoUtils.locale("mine.base_cover") + '</button>' +
                        '<button type="button" id="giveup" class="tempo-button ui-button ui-corner-all ui-widget" ' +
                        'style="height: 28px;line-height: 26px;width: 120px;padding: 0px;margin: 5px 0px;"' +
                        '>' + TempoUtils.locale("mine.base_giveup") + '</button></div>').appendTo($(this));
                    $(this).find("#saveAs").unbind("click").bind("click", function () {
                        saveSceneStrategy['saveAs'](scene, id, e);
                        div.dialog("close");
                    })
                    $(this).find("#cover").unbind("click").bind("click", function () {
                        var divs = $("<div/>").dialog(
                            {
                                width: 230,
                                height: 200,
                                modal: true,
                                open: function () {
                                    var msg = TempoUtils.locale(
                                        "mine.iscover").replace("XXXXX",
                                        res.username);
                                    $("<p style='text-align:center;margin-top:20px;'>" + msg + "</p>")
                                        .appendTo($(this));
                                    $(this.parentElement).find('.ui-dialog-buttonpane.ui-widget-content.ui-helper-clearfix').css("text-align", "center").css("display", "grid");
                                },
                                close: function () {
                                    divs.dialog("destroy").remove();
                                },
                                buttons: [{
                                    text: TempoUtils.locale("mine.publish-dialog-sure"),
                                    click: function () {
                                        saveSceneStrategy['cover'](scene, id, e);
                                        $(this).dialog("close");
                                        div.dialog("close");
                                    }
                                }, {
                                    text: TempoUtils.locale("mine.publish-dialog-cancel"),
                                    click: function () {
                                        $(this).dialog("close");
                                    }
                                }]
                            });
                    })
                    $(this).find("#giveup").unbind("click").bind("click", function () {
                        var divs = $("<div/>").dialog(
                            {
                                width: 230,
                                height: 200,
                                modal: true,
                                open: function () {
                                    var msg = TempoUtils.locale("mine.isgiveup");
                                    $("<p style='text-align:center;margin-top:20px;'>" + msg + "</p>")
                                        .appendTo($(this));
                                    $(this.parentElement).find('.ui-dialog-buttonpane.ui-widget-content.ui-helper-clearfix').css("text-align", "center").css("display", "grid");
                                },
                                close: function () {
                                    divs.dialog("destroy").remove();
                                },
                                buttons: [{
                                    text: TempoUtils.locale("mine.publish-dialog-sure"),
                                    click: function () {
                                        saveSceneStrategy['leave'](res, id, e);
                                        $(this).dialog("close");
                                        div.dialog("close");
                                    }
                                }, {
                                    text: TempoUtils.locale("mine.publish-dialog-cancel"),
                                    click: function () {
                                        $(this).dialog("close");
                                    }
                                }]
                            });
                    })
                },
                close: function () {
                    div.dialog("destroy").remove();
                }
            })
    }


    /**
     * 保存，包括挖掘流、洞察资源库、报告等等
     * 可以指定保存的流程
     * @param e: 保存按钮触发
     * @param analyseId： 保存的分析主题ID
     */
    var mineSave = function (e, analyseId, isRunAfter) {
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var id = analyseId || analyseStatus.getMainId();
        var page = analyseStatus.getFlowPanel(id);
        var data = page.panel.flowpanel('getRootData');
        var insightControlInfos = {
            allInsightIsOpen: false,
            dataInsightIsOpen: true,
            graphInsightIsOpen: true,
            nodeInsightIsOpen: false,
            signalDataInsightIsOpen: true,
        }
        var insightControlInfo = {};
        if (data.insightControlInfo == undefined) {
            insightControlInfo = insightControlInfos;
        } else {
            var insightTarget = $('#insight-setting-more-menu');
            var allInsightIsOpen = insightTarget.find("#allSelectBtn").is(":checked");
            var dataInsightIsOpen = insightTarget.find("#dataCollection").is(":checked");
            var nodeInsightIsOpen = insightTarget.find("#nodeInsight").is(":checked");
            var graphInsightIsOpen = insightTarget.find("#graphInsight").is(":checked");
            var signalDataInsightIsOpen = insightTarget.find("#signalData").is(":checked");
            insightControlInfo.allInsightIsOpen = allInsightIsOpen;
            insightControlInfo.dataInsightIsOpen = dataInsightIsOpen;
            insightControlInfo.nodeInsightIsOpen = nodeInsightIsOpen;
            insightControlInfo.graphInsightIsOpen = graphInsightIsOpen;
            insightControlInfo.signalDataInsightIsOpen = signalDataInsightIsOpen;
        }
        data.insightControlInfo = insightControlInfo;
        if (isRunAfter && isRunAfter == true) {
            //只有提交运行后再把节点信息恢复时tempoSubFullInfo的才是准确的 其他情况tempoSubFullInfo可能不是最新的，导致改动部分被覆盖
            subprocessAdd(data);
        }
        var pro = null;
        if (e) {
            pro = Mask.create();
        }
        //只有当点击执行的时候才修改导入未执行的状态
        //(e && !e.type)这个判断是执行流程时触发的mineSave保存流程；
        //(e && e.type == "runto")这个判断的是执行到当前节点时触发的mineSave保存流程；
        //(e && e.type == "start")这个判断的是从下一个节点开始执行时触发的mineSave保存流程。
        if ((e && !e.type) || (e && e.type == "runto") || (e && e.type == "start")) {
            data.importNotExecuted = false;
            page.panel.flowpanel('updateImportNotExecuted', data.importNotExecuted);
        }
        $.ajax({
            url: contextPath + '/api/ai/resource/save',
            async: false,
            data: {
                id: id,
                content: TempoMineUtils.encodeParams(JSON.stringify(data)),
                lastUpdateTime: analyseStatus.getMainData(id).visitTime || ''
            },
            dataType: 'json',
            type: 'post',
            success: function (result) {
                //如果不是手动保存，则不需要进行提示
                //不提示保存成功
                if (result.success) {
                    var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
                    analyseStatus.addMainData(id, result.data);
                    Eventbus.trigger("mining_board_save.mine", result.data.id);
                    if (e == true) {
                        var page = analyseStatus.getFlowPanel(id);
                        if (!page.panel.flowpanel('isReady')) {
                            $("<div/>").alert({
                                msg: TempoUtils.locale("mine.taskRunningError"),
                                title: TempoUtils.locale("mine.runtask")
                            });
                            return;
                        }
                        Eventbus.trigger('startupFromBar.mine');
                    } else if (e && e.type == "runto") {
                        runToCurrentNode(e.data);
                    } else if (e && e.type == "start") {
                        startRunCurrentNode(e.data);
                    }
                } else {
                    if (result.data) {
                        selectSaveStrategy(result.data, JSON.stringify(data), data.id, e);
                    } else {
                        $("<div/>").alert({
                            msg: result.message,
                            title: TempoUtils.locale("mine.runtask")
                        });
                    }
                }
            },
            error: function (response) {
                var message = TempoUtils.locale("mine.saveFailed");
                if (response.getResponseHeader("Merit-Session-Expired") == "true") {
                    message = TempoUtils.locale("mine.sessionTimeout");
                }
                $("<div/>").alert({
                    msg: message,
                    title: document.title
                });
            },
            complete: function () {
                if (pro) {
                    Mask.hide(pro);
                }
            }
        });
    }

    /**
     *  flowreadyData使得子流程可以避过不通到end端口的线路的节点 [process包含了所有的节点，流程提交时暂时转移到tempoSubFullInfo中]
     * 子流程可以嵌套多次---》所以递归剔除,并补加end端点
     */
    var subprocessDel = function (data) {
        var likeSubprocessNodes = ["minesubprocessnode", "mineloopnode"];
        data.children.forEach(function (v, i) {
            if (likeSubprocessNodes.indexOf(v._widgetName) > -1) {
                console.log("subprocessDel");
                v.tempoSubFullInfo = [];
                v.tempoSubFullInfo.push(v.process.flow.children);
                v.tempoSubFullInfo.push(v.process.flow.connections);
                if (!v.flowReadyData || !v.flowReadyData.connections || !v.flowReadyData.children) {
                    return;
                }
                v.process.flow.connections = v.flowReadyData.connections;
                var tempEnd = null;
                v.process.flow.children.forEach(function (value, index) {
                    if (value.eid == 'END' && value.nodeType == 'END') {
                        tempEnd = value;
                    }
                });
                v.process.flow.children = v.flowReadyData.children;
                if (tempEnd) {
                    v.process.flow.children.push(tempEnd);
                }
                subprocessDel(v.process.flow);
            }
        });
    }
    /**
     * 流程执行完后，将转移到tempoSubFullInfo中存储的节点信息再迁回process中
     * 控制子流程执行完后，本主题下的所有节点[包括黄色/未连接到end端口的节点]的正常显示
     * 子流程可以嵌套多次---》所以递归添加
     */
    var subprocessAdd = function (data) {
        var likeSubprocessNodes = ["minesubprocessnode", "mineloopnode"];
        data.flow.children.forEach(function (v, i) {
            if (likeSubprocessNodes.indexOf(v._widgetName) > -1 && v.tempoSubFullInfo != undefined) {
                console.log("subprocessAdd");
                v.process.flow.children = v.tempoSubFullInfo[0];
                v.process.flow.connections = v.tempoSubFullInfo[1];
                subprocessAdd(v.process);
            }
        });
    }

    /**
     * 执行到当前节点
     */
    var runToCurrentNode = function (curNode) {
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var id = analyseStatus.getMainId();
        var page = analyseStatus.getFlowPanel(id);
        if (!page.panel.flowpanel('isReady')) {
            $("<div/>").alert({
                msg: TempoUtils.locale("mine.taskRunningError"),
                title: TempoUtils.locale("mine.runtask")
            });
            return;
        }
        var board = page.panel.flowpanel('getBoard');
        page.panel.flowpanel('getLastNodeStatus');
        json = board.miningboard("getRunToCurNodeFlowData", curNode);
        //判断注释框的个数
        var numcoms = 0;
        if (json != null) {
            var insightControlInfos = {
                allInsightIsOpen: false,
                dataInsightIsOpen: true,
                graphInsightIsOpen: true,
                nodeInsightIsOpen: false,
                signalDataInsightIsOpen: true,
            }
            var insightControlInfo = {};
            if (json.insightControlInfo == undefined) {
                insightControlInfo = insightControlInfos;
            } else {
                var insightTarget = $('#insight-setting-more-menu');
                var allInsightIsOpen = insightTarget.find("#allSelectBtn").is(":checked");
                var dataInsightIsOpen = insightTarget.find("#dataCollection").is(":checked");
                var nodeInsightIsOpen = insightTarget.find("#nodeInsight").is(":checked");
                var graphInsightIsOpen = insightTarget.find("#graphInsight").is(":checked");
                var signalDataInsightIsOpen = insightTarget.find("#signalData").is(":checked");
                insightControlInfo.allInsightIsOpen = allInsightIsOpen;
                insightControlInfo.dataInsightIsOpen = dataInsightIsOpen;
                insightControlInfo.nodeInsightIsOpen = nodeInsightIsOpen;
                insightControlInfo.graphInsightIsOpen = graphInsightIsOpen;
                insightControlInfo.signalDataInsightIsOpen = signalDataInsightIsOpen;
            }
            json.insightControlInfo = insightControlInfo;
            for (var i = 0; i < json.children.length; i++) {
                var node = json.children[i];
                if (node._widgetName == 'minecommentnode') {
                    numcoms++;
                }
            }
        }
        if (json == null || json.children == null || json.children.length - numcoms == 0) {
            $("<div/>").alert({
                msg: TempoUtils.locale("mine.nodePropError"),
                title: TempoUtils.locale("mine.runtask")
            });
            return;
        }
        board.miningboard("setExcuteStatus", json.children, json.connections);
        var children = json.children;
        for (var i = 0; i < children.length; i++) {
            var childNode = children[i];
            var flowReadyData = childNode.flowReadyData;
            if (!$.isEmptyObject(flowReadyData)) {
                board.miningboard("setExcuteStatus", flowReadyData.children, flowReadyData.connections);
            }
        }
        //  如果流程以及类子流程中包含python编程节点，如果其参与计算，则将其上次你保存的数据库元信息清空
        TempoMineUtils.cleanScriptNodeOutPortMetaOfJson(json);
        page.panel.flowpanel('updateNodeStatus', '');
        page.panel.flowpanel('clearFlowLog');
        subprocessDel(json);
        var pro = Mask.create({text: TempoUtils.locale("mine.taskIsRunning")});
        $.ajax({
            url: contextPath + "/api/ai/mine/startNodeExcuteFlow",
            data: {
                flow: TempoMineUtils.encodeParams(JSON.stringify(json)),
                flowId: id,
                analyseId: window[constant.ANALYSE_ID]
            },
            type: 'post',
            success: function (result) {
                page.panel.flowpanel('showFlowLog', result.message);
                if (result.status) {
                    // 清空各个节点的执行状态
                    //page.panel.flowpanel('updateNodeStatus', '', curNode);
                    page.panel.flowpanel('startStatusTimer', result.exid,
                        result.mineServiceInfo);
                }
                //mineSave();
                mineSave(null, null, true);
            },
            error: function (response) {
                var message = TempoUtils.locale("mine.runtaskError");
                if (response.getResponseHeader("Merit-Session-Expired") == "true") {
                    message = TempoUtils.locale("mine.sessionTimeout");
                }
                $("<div/>").alert({
                    msg: message,
                    title: document.title
                });
            },
            complete: function () {
                Mask.hide(pro);
            }
        })
    }

    /**
     * 从当前节点开始执行
     */
    var startRunCurrentNode = function (curNode) {
        curNode[curNode.attr("_widgetname")]("deleteNextCache");
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var id = analyseStatus.getMainId();
        var page = analyseStatus.getFlowPanel(id);
        if (!page.panel.flowpanel('isReady')) {
            $("<div/>").alert({
                msg: TempoUtils.locale("mine.taskRunningError"),
                title: TempoUtils.locale("mine.runtask")
            });
            return;
        }
        var board = page.panel.flowpanel('getBoard');
        page.panel.flowpanel('getLastNodeStatus');
        var skipExcuteNodeIds = board.miningboard("getNeedExcuteNodeIds", curNode);

        json = board.miningboard("getFlowData");
        //判断注释框的个数
        var numcoms = 0;
        if (json != null) {
            var insightControlInfos = {
                allInsightIsOpen: false,
                dataInsightIsOpen: true,
                graphInsightIsOpen: true,
                nodeInsightIsOpen: false,
                signalDataInsightIsOpen: true,
            }
            var insightControlInfo = {};
            if (json.insightControlInfo == undefined) {
                insightControlInfo = insightControlInfos;
            } else {
                var insightTarget = $('#insight-setting-more-menu');
                var allInsightIsOpen = insightTarget.find("#allSelectBtn").is(":checked");
                var dataInsightIsOpen = insightTarget.find("#dataCollection").is(":checked");
                var nodeInsightIsOpen = insightTarget.find("#nodeInsight").is(":checked");
                var graphInsightIsOpen = insightTarget.find("#graphInsight").is(":checked");
                var signalDataInsightIsOpen = insightTarget.find("#signalData").is(":checked");
                insightControlInfo.allInsightIsOpen = allInsightIsOpen;
                insightControlInfo.dataInsightIsOpen = dataInsightIsOpen;
                insightControlInfo.nodeInsightIsOpen = nodeInsightIsOpen;
                insightControlInfo.graphInsightIsOpen = graphInsightIsOpen;
                insightControlInfo.signalDataInsightIsOpen = signalDataInsightIsOpen;
            }
            json.insightControlInfo = insightControlInfo;
            for (var i = 0; i < json.children.length; i++) {
                var node = json.children[i];
                if (node._widgetName == 'minecommentnode') {
                    numcoms++;
                }
            }
        }
        if (json == null || json.children == null || json.children.length - numcoms == 0) {
            $("<div/>").alert({
                msg: TempoUtils.locale("mine.nodePropError"),
                title: TempoUtils.locale("mine.runtask")
            });
            return;
        }
        var children = json.children;
        if (children && children.length && children.length > 0) {
            for (var i = 0; i < children.length; i++) {
                var childNode = children[i];
                var eid = childNode.eid;
                var parameters = childNode.parameters;
                parameters.excuteFlowType = "startNodeExcute";
                if (skipExcuteNodeIds.indexOf(eid) == -1) {
                    parameters.isNeedExcute = false;
                    var flowReadyData = childNode.flowReadyData;
                    if (flowReadyData) {

                        var subprocessChildren = flowReadyData.children;
                        if (subprocessChildren && subprocessChildren.length && subprocessChildren.length > 0) {
                            for (var j = 0; j < subprocessChildren.length; j++) {
                                var subprocessChildNode = subprocessChildren[j];
                                var subprocessParameters = subprocessChildNode.parameters;
                                if (!$.isEmptyObject(subprocessParameters)) {
                                    subprocessParameters.isNeedExcute = false;
                                    subprocessParameters.excuteFlowType = "startNodeExcute";
                                }
                            }
                        }
                    }
                }
            }
        }
        //  如果流程以及类子流程中包含python编程节点，如果其参与计算，则将其上次你保存的数据库元信息清空
        TempoMineUtils.cleanScriptNodeOutPortMetaOfJson(json);
        page.panel.flowpanel('updateNodeStatus', '');
        page.panel.flowpanel('clearFlowLog');
        subprocessDel(json);
        var pro = Mask.create({text: TempoUtils.locale("mine.taskIsRunning")});
        $.ajax({
            url: contextPath + "/api/ai/mine/startNodeExcuteFlow",
            data: {
                flow: TempoMineUtils.encodeParams(JSON.stringify(json)),
                flowId: id,
                analyseId: window[constant.ANALYSE_ID],
            },
            type: 'post',
            success: function (result) {
                page.panel.flowpanel('showFlowLog', result.message);
                if (result.status) {
                    // 清空各个节点的执行状态
                    //page.panel.flowpanel('updateNodeStatus', '');
                    page.panel.flowpanel('startStatusTimer', result.exid,
                        result.mineServiceInfo);
                }
                //mineSave();
                mineSave(null, null, true);
            },
            error: function (response) {
                var message = TempoUtils.locale("mine.runtaskError");
                if (response.getResponseHeader("Merit-Session-Expired") == "true") {
                    message = TempoUtils.locale("mine.sessionTimeout");
                }
                $("<div/>").alert({
                    msg: message,
                    title: document.title
                });
            },
            complete: function () {
                Mask.hide(pro);
            }
        })
    }

    /**
     * 校验当前复制的节点是否存在pl管道支持的节点
     * @param nodeList
     * @returns {boolean} true为存在  false为不存在
     */
    var checkCopyNodeIfExistsPLNode = function (nodeList) {
        var isCanCopy = false;
        if (nodeList && nodeList.length > 0) {
            nodeList.forEach(function (node, index) {
                //获取是否是管道(PL)节点的标识
                var isSupportPL = node.config.isSupportPL;
                if (isSupportPL != undefined && (isSupportPL == true || isSupportPL == 'true')) {
                    isCanCopy = true;
                    //发现当前复制的节点有pl管道节点就立刻退出循环
                    return false;
                }
            });
        }
        return isCanCopy;
    }

    /**
     * 初始化面板的右键单击事件
     */
    var initBoardMenu = function (e, board) {
        var disabled = $('#' + $(board).attr('flow-panel')).flowpanel('isRunning');
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var nodeList = analyseStatus.get("copyNodeList");
        var board = $('#' + parentId);
        var flow = board.miningboard("getJson");
        //获取当前面板是显示注释还是隐藏注释 true为显示 false为隐藏
        var comsflag = flow.comsflag;
        var dataMenu = [];
        //用来记录面板有多少个注释框
        var num = 0;
        //面板所有节点的数据
        var childNodes = flow.children;
        if (childNodes && childNodes.length && childNodes.length > 0) {
            for (var i = 0; i < childNodes.length; i++) {
                var childNodeData = childNodes[i];
                if (TempoUtils.equals(childNodeData.nodeType, "commentbox")) {
                    num = num + 1;
                }
            }
        }
        //获取当前流程类型
        var flowType = Eventbus.triggerHandler("getFlowType.mine")[0];
        //校验当前复制的节点是否存在pl管道支持的节点
        var ifExistsPLNode = checkCopyNodeIfExistsPLNode(nodeList);
        //只有nodeList有东西菜单才显示粘贴
        if (nodeList && nodeList.length > 0) {
            if (comsflag) {
                //当comsflag为true时，菜单是隐藏全部注释
                if (num == 0) {
                    dataMenu = [
                        {
                            text: TempoUtils.locale("commentbox.addprocesscomments"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-addprocesscomments',
                            id: 'addprocoms',
                            disabled: disabled
                        },
                        {
                            text: TempoUtils.locale("mine.mine_paste"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-paste',
                            id: 'paste',
                            disabled: disabled
                        }
                    ];
                } else {
                    dataMenu = [
                        {
                            text: TempoUtils.locale("commentbox.addprocesscomments"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-addprocesscomments',
                            id: 'addprocoms',
                            disabled: disabled
                        },
                        {
                            text: TempoUtils.locale("commentbox.hideallcomments"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-hideallcomments',
                            id: 'allcoms',
                            disabled: disabled
                        },
                        {
                            text: TempoUtils.locale("mine.mine_paste"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-paste',
                            id: 'paste',
                            disabled: disabled
                        }
                    ];
                    if (flow.name == "子流程" ||
                        flow.name == "bagging回归" ||
                        flow.name == "bagging分类" ||
                        flow.name == "自动择参" ||
                        flow.name == "分类交叉验证" ||
                        flow.name == "回归交叉验证" ||
                        flow.name == "循环行") {
                        dataMenu[1].disabled = true;
                    }
                }
            } else {
                //当comsflag为false时，菜单是显示全部注释，并且没有添加流程注释
                //注释隐藏就算有复制的东西也隐藏粘贴菜单
                if (nodeList["0"].data.nodeType == "commentbox") {
                    dataMenu = [
                        {
                            text: TempoUtils.locale("commentbox.showallcomments"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-showallcomments',
                            id: 'allcoms',
                            disabled: disabled
                        }
                    ];
                } else {
                    dataMenu = [
                        {
                            text: TempoUtils.locale("commentbox.showallcomments"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-showallcomments',
                            id: 'allcoms',
                            disabled: disabled
                        },
                        {
                            text: TempoUtils.locale("mine.mine_paste"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-paste',
                            id: 'paste',
                            disabled: disabled
                        }
                    ];
                }
                if (flow.name == "子流程" ||
                    flow.name == "bagging回归" ||
                    flow.name == "bagging分类" ||
                    flow.name == "自动择参" ||
                    flow.name == "分类交叉验证" ||
                    flow.name == "回归交叉验证" ||
                    flow.name == "循环行") {
                    dataMenu[0].disabled = true;
                }
            }
        } else {
            if (comsflag) {
                //当comsflag为true时，菜单是隐藏全部注释
                if (num == 0) {
                    dataMenu = [
                        {
                            text: TempoUtils.locale("commentbox.addprocesscomments"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-addprocesscomments',
                            id: 'addprocoms',
                            disabled: disabled
                        }
                    ];
                } else {
                    dataMenu = [
                        {
                            text: TempoUtils.locale("commentbox.addprocesscomments"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-addprocesscomments',
                            id: 'addprocoms',
                            disabled: disabled
                        },
                        {
                            text: TempoUtils.locale("commentbox.hideallcomments"),
                            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-hideallcomments',
                            id: 'allcoms',
                            disabled: disabled
                        }
                    ];
                    if (flow.name == "子流程" ||
                        flow.name == "bagging回归" ||
                        flow.name == "bagging分类" ||
                        flow.name == "自动择参" ||
                        flow.name == "分类交叉验证" ||
                        flow.name == "回归交叉验证" ||
                        flow.name == "循环行") {
                        dataMenu[1].disabled = true;
                    }
                }
            } else {
                //当comsflag为false时，菜单是显示全部注释，并且没有添加流程注释
                dataMenu = [
                    {
                        text: TempoUtils.locale("commentbox.showallcomments"),
                        icon: 'ui-icon tempo-ui-icon tempo-ui-icon-showallcomments',
                        id: 'allcoms',
                        disabled: disabled
                    }
                ];
                if (flow.name == "子流程" ||
                    flow.name == "bagging回归" ||
                    flow.name == "bagging分类" ||
                    flow.name == "自动择参" ||
                    flow.name == "分类交叉验证" ||
                    flow.name == "回归交叉验证" ||
                    flow.name == "循环行") {
                    dataMenu[0].disabled = true;
                }
            }
        }
        //当前流程类型为管道流程并且复制的节点不存在pl管道节点，则需要将粘贴禁用
        if (flowType == "plflow" && !ifExistsPLNode) {
            for (var i = 0; i < dataMenu.length; i++) {
                if (dataMenu[i].id && dataMenu[i].id == 'paste') {
                    dataMenu[i].disabled = true;
                }
            }
        }
        //增加下载文件列表菜单
        dataMenu.push({
            text: TempoUtils.locale("writefilebatch.downloadFileList"),
            icon: 'ui-icon tempo-ui-icon tempo-ui-icon-download',
            id: 'downloadfile',
            disabled: disabled
        })
        //先移除再渲染
        var menu = $('ul.miningnodepro-menu');
        if (!menu.length) {
            menu.remove();
        }
        boardMenu = $("<ul/>").addClass('miningnodepro-menu').contextmenu({
            data: dataMenu,
            select: function (e, ui) {
                e.stopPropagation();
                selectBoardMenu(e, ui);
            },
            close: function () {
                boardMenu.contextmenu("enableAll").contextmenu("collapseAll");
            }
        }).appendTo($("body"));

        boardMenu.bind("contextmenu", function (e) {
            e.preventDefault();
        });
        $("body").bind('click.contextmenu', function (e) {
            boardMenu.contextmenu('hide');
        })

        //显示菜单
        boardMenu.contextmenu("show", {
            linkEl: board,
            position: {
                left: e.pageX,
                top: e.pageY
            }
        });
        e.preventDefault();
    }

    /**
     * 面板按钮选择事件
     */
    var selectBoardMenu = function (e, ui) {
        var id = ui.select.id;
        if ("paste" == id) {
            pasteNode(e, ui);
        } else if ("addprocoms" == id) {
            addProComs();
        } else if ("allcoms" == id) {
            AllComs(e, ui);
        } else if ("downloadfile" == id) {
            //下载文件列表弹框初始化
            initDownloadFileDialog();
        }
    }

    /**
     * 下载文件列表弹框初始化
     */
    var initDownloadFileDialog = function () {
        //打开之前先删除之前的框
        $("#file-list-dialog").remove();
        var myDiv = $("#tempo-mine-write-file-batch-file-list-dialog-temp");
        var mHtml = myDiv.html();
        var fileListDialog = $('<div style="width: 100%;height: 100%;"/></div>').attr("id", "file-list-dialog").html(mHtml);
        fileListDialog.dialog({
            title: TempoUtils.locale("writefilebatch.fileListTitle"),
            autoOpen: true,
            width: 880,
            height: 650,
            resizable: false,
            modal: true,
            close: function () {
                fileListDialog.dialog('destroy');
            },
            open: function () {
                //初始化弹框配置页组件
                initFileListHeader(fileListDialog);
                //初始化文件列表
                initFileListTable(fileListDialog);
            }
        });
    }

    /**
     * 初始化文件列表头部批量操作和搜索区域组件
     * @param fileListDialog
     */
    var initFileListHeader = function (fileListDialog) {

        //批量删除按钮初始化
        fileListDialog.find("#tempo-mine-write-file-batch-file-list-batch-delete").unbind("click").bind("click", function () {
            //获取到文件列表dom元素
            var grid = fileListDialog.find("#tempo-mine-write-file-batch-file-list-div-table");
            //获取所有选中行id
            var selectRowIds = grid.datagrid("getCheckedRowIds");
            if (selectRowIds.length == 0) {
                //请至少勾选一个文件进行删除
                showTip(TempoUtils.locale("writefilebatch.fileDeleteTip1"));
                return;
            }
            $("<div/>").confirm({
                title: TempoUtils.locale("mine.publish-btn-delete"),
                msg: TempoUtils.locale("writefilebatch.fileDeleteTip2"),
                height: showTipHeight,
                width: showTipWidth,
                ok: function () {
                    var rowDataList = [];
                    for (var i = 0; i < selectRowIds.length; i++) {
                        var rowData = grid.datagrid("getRowData", selectRowIds[i]);
                        rowDataList.push(rowData.fileId);
                    }
                    //批量删除事件
                    batchDeleteFile(rowDataList, fileListDialog, true, selectRowIds.length == grid.datagrid("getRowData").length);
                }
            });
        });

        //下拉框初始化
        fileListDialog.find("#tempo-mine-write-file-batch-file-list-owning-module").selectmenu({
            width: 150,
            height: 28,
            select: function (e, ui) {
            }
        });
        fileListDialog.find("#tempo-mine-write-file-batch-file-list-owning-module").next().css("float", "right").hide();
        fileListDialog.find("#tempo-mine-write-file-batch-file-list-owning-module-label").hide();

        //搜索框初始化
        fileListDialog.find("#tempo-mine-write-file-batch-file-list-search-name").searchbar({
            auto: true,
            width: 181,
            height: 27,
            placeholder: TempoUtils.locale("writefilebatch.fileNameTip4"),
            onSearch: function (text) {
                fileListDialog.find("#tempo-mine-write-file-batch-file-list-div-table")
                    .datagrid("reloadGrid", {
                        //范围
                        range: "app",
                        //应用id
                        appId: window[constant.ANALYSE_ID],
                        //流程id
                        flowId: window.analyseStatus.getMainId(),
                        //节点id
                        nodeId: "",
                        //搜索文件名称
                        searchFileName: text,
                    });
            }
        });
        //设置样式
        fileListDialog.find("#tempo-mine-write-file-batch-file-list-search-name-label")
            .css("float", "right").css("line-height", "26px").css("margin-righ", "10px");
    }

    /**
     * 处理数据
     * @param value
     * @returns {string|string|*}
     */
    var formatter = function (value) {
        return TempoMineUtils.encodeHTML(value);
    }

    /**
     * 处理日期
     * @param value
     * @returns {*}
     */
    var formatterDate = function (value) {
        if (typeof value == "number") {
            return DateUtils.formatDateTime((new Date(value)));
        }
        return value;
    }

    /**
     * 初始化表格
     * @param fileListDialog
     */
    var initFileListTable = function (fileListDialog) {
        var colName = ["<input id='jqgridUpdate' class='tempo-checkbox' type='checkbox'><label for='jqgridUpdate'> </label>",
            TempoUtils.locale("writefilebatch.fileId"), TempoUtils.locale("writefilebatch.flowName"),
            TempoUtils.locale("writefilebatch.nodeName"), TempoUtils.locale("writefilebatch.fileSize"),
            TempoUtils.locale("writefilebatch.fileName"), TempoUtils.locale("writefilebatch.fileType"),
            TempoUtils.locale("writefilebatch.fileLocation"), TempoUtils.locale("writefilebatch.createTime"),
            TempoUtils.locale("writefilebatch.validTime"), TempoUtils.locale("writefilebatch.operate")];
        var colModel = [{
            name: 'updateselect',
            index: 'updateselect',
            width: '1px',
            sortable: false,
            hidden: true
        }, {
            name: 'fileId',
            index: 'fileId',
            width: '1px',
            sortable: false,
            hidden: true
        }, {
            name: 'flowName',
            index: 'flowName',
            width: '60px',
            formatter: formatter,
            editable: false
        }, {
            name: 'nodeName',
            index: 'nodeName',
            width: '60px',
            formatter: formatter,
            editable: false
        }, {
            name: 'fileSize',
            index: 'fileSize',
            width: '60px',
            formatter: formatter,
            editable: false
        }, {
            name: 'fileName',
            index: 'fileName',
            width: '60px',
            formatter: formatter,
            editable: false
        }, {
            name: 'fileType',
            index: 'fileType',
            width: '60px',
            formatter: formatter,
            editable: false
        }, {
            name: 'fileLocation',
            index: 'fileLocation',
            width: '1px',
            sortable: false,
            hidden: true
        }, {
            name: 'createTime',
            index: 'createTime',
            width: '97px',
            formatter: formatterDate,
            editable: false
        }, {
            name: 'validTime',
            index: 'validTime',
            width: '97px',
            formatter: formatterDate,
            editable: false
        }, {
            name: 'operate',
            index: 'operate',
            width: '70px',
            editable: false,
            buttons: [{
                id: "view",
                icon: "ui-button-icon ui-icon tempo-ui-icon tempo-ui-icon-viewdata",
                title: TempoUtils.locale("writefilebatch.view"),
                click: function (e, dt) {
                    //点击操作按钮时，不进行行的选中和取消选中
                    fileListTable.datagrid("setSelection", dt.rowId, !fileListTable.find("#" + dt.rowId).find("input").prop("checked"));
                    //查看事件
                    viewFile(dt.rowData);
                }
            }, {
                id: "download",
                title: TempoUtils.locale("writefilebatch.download"),
                icon: "ui-icon tempo-ui-icon tempo-ui-icon-download",
                click: function (e, dt) {
                    //点击操作按钮时，不进行行的选中和取消选中
                    fileListTable.datagrid("setSelection", dt.rowId, !fileListTable.find("#" + dt.rowId).find("input").prop("checked"));
                    //下载事件
                    downloadFile(dt.rowData);
                }
            }, {
                id: "delete",
                title: TempoUtils.locale("writefilebatch.delete"),
                icon: "ui-icon tempo-ui-icon tempo-ui-icon-delete",
                click: function (e, dt) {
                    //点击操作按钮时，不进行行的选中和取消选中
                    fileListTable.datagrid("setSelection", dt.rowId, !fileListTable.find("#" + dt.rowId).find("input").prop("checked"));
                    //删除事件
                    $("<div/>").confirm({
                        title: TempoUtils.locale("mine.publish-btn-delete"),
                        msg: TempoUtils.locale("writefilebatch.fileDeleteTip2"),
                        height: showTipHeight,
                        width: showTipWidth,
                        ok: function () {
                            //删除事件
                            var rowDataList = [];
                            rowDataList.push(dt.rowData.fileId);
                            batchDeleteFile(rowDataList, fileListDialog, false, fileListTable.datagrid("getRowData").length == 1);
                        }
                    });
                }
            }]
        }];
        var fileListDiv = fileListDialog.find("#tempo-mine-write-file-batch-file-list-div").html("");
        var fileListTable = $("<table id='tempo-mine-write-file-batch-file-list-div-table'></table>").appendTo(fileListDiv);
        fileListTable.datagrid({
            datatype: "json",
            url: contextPath + '/api/ai/node/io/writefile/list-files?time=' + new Date().getTime(),
            postData: {
                //范围
                range: "app",
                //应用id
                themeId: window[constant.ANALYSE_ID],
                //流程id
                flowId: window.analyseStatus.getMainId(),
                //节点id
                nodeId: "",
                //搜索文件名称
                searchFileName: "",
            },
            fit: true,
            autowidth: true,
            //分割线
            separator: true,
            mtype: 'POST',
            colNames: colName,
            colModel: colModel,
            rowNum: 10,
            rownumbers: true,
            shrinkToFit: true,
            viewrecords: true,
            pagination: true,
            striped: true,
            loadonce: true,
            multiselect: true,
            showRefreshBth: true,
            loadComplete: function () {
                //初始化单选事件
                fileListTable.find("input").checkbox({
                    change: function () {
                        //获取勾选选中行id
                        var checkedRowIds = fileListTable.datagrid('getCheckedRowIds');
                        //获取所有行id
                        var rowIds = fileListTable.datagrid('getRowIds');
                        //获取全选按钮DOM元素
                        var input = fileListTable.parent().parent().prev().find("input[id$='_tempo-mine-write-file-batch-file-list-div-table']");
                        input.checkbox("option", "checked", checkedRowIds.length == rowIds.length);
                    }
                });
            }
        });
        //将排序class移除，否则点击表头会触发接口调用
        fileListDiv.find(".ui-jqgrid-sortable").removeClass("ui-jqgrid-sortable");
    }

    /**
     * 查看事件
     * @param rowData 行数据
     */
    var viewFile = function (rowData) {
        var fileId = rowData.fileId;
        var process = $("<div/>").tempoprogressbar();
        $.ajax({
            url: contextPath + "/api/ai/node/io/writefile/get-file-info",
            data: {
                fileId: fileId,
            },
            type: 'POST',
            success: function (result) {
                if (result && result.success) {
                    var dataDialog = $('<div style="width:100%;height:100%;"/></div>')
                    dataDialog.dialog({
                        title: TempoUtils.locale("writefilebatch.dataView"),
                        autoOpen: true,
                        width: 750,
                        height: 420,
                        resizable: false,
                        modal: true,
                        close: function () {
                            dataDialog.dialog('destroy');
                        },
                        open: function () {
                            TempoMineInsightUtils.writeFileDataView(result.data, dataDialog);
                        }
                    });
                } else {
                    showTip(result.message ? result.message : "接口异常");
                }
            },
            complete: function () {
                process.tempoprogressbar("destroy");
            },
            error: function () {
            }
        });
    }

    /**
     * 下载事件
     */
    var downloadFile = function (rowData) {
        //超过有效期无法下载
        var validTime = rowData.validTime;
        var nowTime = new Date().getTime();
        if (nowTime > validTime) {
            //文件已失效，请检查！
            showTip(TempoUtils.locale("writefilebatch.fileValidTimeTip"));
            return;
        }
        var process = $("<div/>").tempoprogressbar();
        //调用接口判断文件是否存在
        $.ajax({
            url: contextPath + "/api/ai/node/io/writefile/file-is-exists",
            type: 'post',
            data: {
                fileId: rowData.fileId,
            },
            success: function (rs) {
                if (rs.success) {
                    //存在则下载文件
                    downloadFiles({
                        url: contextPath + "/api/ai/node/io/writefile/file-download",
                        data: {
                            fileId: rowData.fileId,
                        }
                    });
                } else {
                    //不存在则提示
                    TempoUtils.showTip(rs.message);
                }
            },
            complete: function () {
                process.tempoprogressbar("destroy");
            },
            error: function () {
            }
        });
    }

    /**
     * 文件输出节点下载文件 ie11下文件下载不可用问题
     * 对汉字进行16进制编码
     */
    var downloadFiles = function (options) {
        for (var key in options.data) {
            options.data[key] = encodeURI(options.data[key]);
        }
        TempoUtils.download(options);
    };

    /**
     * 删除事件
     * @param rowDataList 文件ID
     * @param fileListDialog 文件列表弹框
     * @param isBatch 是否是批量删除
     * @param isNeedJump 是否需要切换至上一页
     */
    var batchDeleteFile = function (rowDataList, fileListDialog, isBatch, isNeedJump) {
        var process = $("<div/>").tempoprogressbar();
        $.ajax({
            url: contextPath + "/api/ai/node/io/writefile/batch-delete",
            type: 'post',
            data: {
                fileIds: rowDataList.join(","),
                isBatch: isBatch,
            },
            success: function (rs) {
                //文件删除成功
                showTip(TempoUtils.locale("writefilebatch.fileDeleteSuccessTip"));
                //获取到文件列表dom元素
                var grid = fileListDialog.find("#tempo-mine-write-file-batch-file-list-div-table");
                //删除后是否需要跳转到上一页
                if (isNeedJump) {
                    //获取当前分页
                    var page = grid.datagrid("getGridParam", "page");
                    //设置跳转到上一页，若上一页小于等于第一页则为第一页
                    grid.datagrid("setGridParam", {page: (page - 1) <= 1 ? 1 : page - 1});
                }
                grid.datagrid("reloadGrid", {
                    //范围
                    range: "app",
                    //应用id
                    appId: window[constant.ANALYSE_ID],
                    //流程id
                    flowId: window.analyseStatus.getMainId(),
                    //节点id
                    nodeId: "",
                    //搜索文件名称
                    searchFileName: fileListDialog.find("#tempo-mine-write-file-batch-file-list-search-name").searchbar("getValue"),
                }, true, false);
            },
            complete: function () {
                process.tempoprogressbar("destroy");
            },
            error: function () {
            }
        });
    }

    /**
     * 校验是否要粘贴节点
     * @param evt
     * @param ui
     * @param nodeList
     * @param isCheck
     * @param flowType
     */
    var checkIfPasteNode = function (evt, ui, nodeList, isCheck, flowType) {
        //校验是否要粘贴（框选复制可能存在普通节点和管道(PL)节点）
        if (nodeList.length > 0 && (isCheck == undefined || !isCheck) && flowType && flowType == "plflow") {
            var ifExistPLNode = false;
            nodeList.forEach(function (node, index) {
                //获取是否是管道(PL)节点的标识
                var isSupportPL = node.config.isSupportPL;
                if (isSupportPL != undefined && (isSupportPL == true || isSupportPL == 'true')) {
                    ifExistPLNode = true;
                    return false;
                }
            });
            var ifExistOrdinaryNode = false;
            nodeList.forEach(function (node, index) {
                //获取是否是管道(PL)节点的标识
                var isSupportPL = node.config.isSupportPL;
                if (isSupportPL == undefined || isSupportPL == false || isSupportPL == 'false') {
                    ifExistOrdinaryNode = true;
                    return false;
                }
            });
            //复制的节点同时存在普通节点和管道(PL)节点时需要弹框提示
            if (ifExistPLNode && ifExistOrdinaryNode) {
                $('<div id="tempo-multiline-dialog">').appendTo($('body')).dialog({
                    title: "复制粘贴节点",
                    modal: true,
                    width: 300,
                    height: 250,
                    resizable: false,
                    open: function () {
                        $('<div style="display: table; width: 100%; height: 100%;">' +
                            '<p style="display: table-cell; vertical-align: middle;">' +
                            '管道中仅支持带有PL标识的节点，粘贴后会存在部分节点和连线丢失，确认粘贴？</p></div>').appendTo($(this));
                    },
                    close: function () {
                        $(this).dialog("destroy").remove();
                    },
                    buttons: [{
                        text: TempoUtils.locale("core.ok"),
                        click: function () {
                            pasteNode(evt, ui, true);
                            $(this).dialog("close");
                        }
                    }, {
                        text: TempoUtils.locale("core.cancel"),
                        click: function () {
                            //取消的同时也删除元素
                            $(this).dialog("close");
                        }
                    }],
                })
                //弹框终止本次方法
                return false;
            }
        }
        return true;
    }

    /**
     * 粘贴复制的节点
     */
    var pasteNode = function (evt, ui, isCheck) {
        //获取要粘贴的节点和连线信息
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var nodeList = JSON.parse(JSON.stringify(analyseStatus.get("copyNodeList")));
        //获取当前流程类型
        var flowType = Eventbus.triggerHandler("getFlowType.mine")[0];
        if (!checkIfPasteNode(evt, ui, nodeList, isCheck, flowType)) {
            return;
        }
        //将管道流程节点过滤出来
        if (flowType == "plflow") {
            nodeList = nodeList.filter(function (node, index) {
                //获取是否是管道(PL)节点的标识
                var isSupportPL = node.config.isSupportPL;
                return isSupportPL != undefined && (isSupportPL == true || isSupportPL == 'true');
            });
        }
        //保存当前粘贴的所有节点的节点id
        var nodeIdList = [];
        nodeList.forEach(function (node, index) {
            nodeIdList.push(node.data.eid);
        });
        //框选复制不包括节点本身的节点注释时，将节点注释脱离节点变成流程注释
        nodeList.forEach(function (node, index) {
            if (node.config.id == "commentbox" && node.data.nodeUuid) {
                var split = node.data.nodeUuid.split("_");
                if (split.length >= 3 && nodeIdList.indexOf(split[0]) == -1) {
                    node.data.parameters.comment_type = "process_comment";
                    delete node.data.parameters.nodeUuid;
                    delete node.data.parameters.noteUuid;
                }
            }
        });
        var progressbar = $("<div/>").tempoprogressbar();
        setTimeout(function () {
            var connectionList = TempoUtils.clone(analyseStatus.get("copyNodeConnections") || []);
            if (connectionList.length > 0) connectionList = JSON.parse(JSON.stringify(connectionList));
            /**
             * 更新连线的UUid
             * @param oldEid
             * @param newEid
             */
            var updateConnectionUuIds = function (oldEid, newEid) {
                $.each(connectionList, function (i, item) {
                    $.each(item, function (j, point) {
                        var pointSplitArray = point.split("_");
                        if (pointSplitArray.length >= 3 && (pointSplitArray[0] == oldEid)) {
                            item[j] = newEid + "_" + pointSplitArray[1] + "_" + pointSplitArray[2];
                        }
                    });
                })
            };

            /**
             * 更改开启注释节点的节点的eid和nodeUuid
             * @param nodeUuid
             * @param newNodeUuid
             */
            var changeEnableCommentNodeEid = function (nodeUuid, newNodeUuid) {
                nodeList.forEach(function (node, index) {
                    if (node.data.nodeType !== "commentbox" && node.data.eid === nodeUuid) {
                        node.data.eid = newNodeUuid;
                        node.data.nodeUuid = newNodeUuid;
                        node.data.oldEid = nodeUuid;
                        node.data.signIsChange = true;
                    }
                })
            };

            if (nodeList.length > 0) {
                var board = null;
                var minLeft = Infinity;
                var minTop = Infinity;
                //寻找节点中最小的left和top
                nodeList.forEach(function (node, index) {
                    if (node.x < minLeft) {
                        minLeft = node.x;
                    }
                    if (node.y < minTop) {
                        minTop = node.y;
                    }
                });
                //用于存储新的节点eid
                var newNodeId = [];
                nodeList.forEach(function (node, index) {
                    var boardId = analyseStatus.getMainId();
                    var panel = analyseStatus.getFlowPanel(boardId).panel;
                    board = panel.flowpanel('getBoard');
                    var alias = _getAlias({name: node.data.alias, id: node.config.id}, board);
                    var data = TempoUtils.clone(node.data);
                    var oldEid = data.signIsChange == true ? data.oldEid : data.eid;
                    var newEid = data.signIsChange == true ? data.eid : TempoUtils.uuid();

                    delete data.signIsChange;
                    delete data.oldEid;
                    delete node.data.signIsChange;
                    delete node.data.oldEid;

                    var opts = $.extend({}, data, {style: {}, alias: alias, eid: newEid, status: ''});

                    //如果是注释节点，noteUuid为注释节点的eid，nodeUuid为开启注释节点的节点的eid
                    if (data.nodeType == "commentbox") {
                        //复制注释节点需要增加zIndex
                        opts = $.extend({}, data, {
                            style: JSON.parse(JSON.stringify(data.style)),
                            alias: alias,
                            eid: newEid,
                            status: ''
                        });

                        if (opts.noteUuid) {
                            opts.noteUuid = opts.noteUuid.replace(oldEid, newEid);
                        }

                        //更改nodeUuid为新的
                        if (opts.nodeUuid && opts.parameters.comment_type != "process_comment") {
                            var newNodeUuid = TempoUtils.uuid();
                            //修改开启注释节点的节点，修改该节点的uuid
                            var nodeEid = opts.nodeUuid.split("_")[0];
                            opts.parameters.comment_type = opts.parameters.comment_type.replace(nodeEid, newNodeUuid);
                            changeEnableCommentNodeEid(nodeEid, newNodeUuid);
                            opts.nodeUuid = opts.nodeUuid.replace(nodeEid, newNodeUuid);
                        }
                    } else {
                        if (opts.nodeUuid) {
                            opts.nodeUuid = opts.nodeUuid.replace(oldEid, newEid);
                        }
                    }

                    updateConnectionUuIds(oldEid, newEid);
                    opts.parameters && (opts.parameters._isedit = false);
                    //添加特殊判断 对特定节点的特定端口不给予删除
                    var speacialNode = ["fpgrowth", "apriori", "randomsplitdataset", "textTF"];//这三个节点保留数据端口+1个模型端口
                    if (speacialNode.indexOf(node.config.id) > -1) {
                        var temp = [];
                        opts.scope.outScope.forEach(function (v, i) {
                            if (v.type != "model" || v.code == "model") {
                                temp.push(v);
                            }
                        })
                        opts.scope.outScope = temp;
                    } else if (!opts.disableDeleteScope) {
                        //注释掉该行代码，节点复制粘贴后保留原先旧的端口
                        delete opts.scope;
                    } else {
                        delete opts.disableDeleteScope;
                    }
                    if (nodeLimit(panel, node.config)) return;
                    //设置黑名单，将此类节点的配置信息清除
                    var blacklist = ['readdatabank', 'readfile'];
                    if (blacklist.indexOf(opts.nodeType) > -1) {
                        opts._forceConfirm = true;
                    }

                    if (opts.process) {
                        opts.process.id && (opts.process.id = TempoUtils.uuid());
                        opts.process.parentNodeId && (opts.process.parentNodeId = opts.eid);
                        //复制节点时-修改自动择参节点内部算法节点id及相关连线->子流程节点均有此问题
                        var parentNodeArray = ["parameterselect", "bagging", "regressionBagging", "loopsampledata", "subprocess", "regcrossvalidation", "clacrossvalidation"];
                        if (parentNodeArray.indexOf(opts.nodeType) != -1) {
                            if (opts.process.flow.children) {
                                //给children进行排序，注释节点在前面
                                var targetCopyList = [];
                                var childrenList = opts.process.flow.children;
                                var childrenLength = childrenList.length;
                                for (var i = 0; i < childrenLength; i++) {
                                    if (childrenList[i].nodeType === "commentbox") {
                                        targetCopyList.push(childrenList[i])
                                    }
                                }
                                for (var i = 0; i < childrenLength; i++) {
                                    if (childrenList[i].nodeType !== "commentbox") {
                                        targetCopyList.push(childrenList[i])
                                    }
                                }
                                opts.process.flow.children = targetCopyList;

                                var changeCommentNodeEid = function (nodeUuid, newNodeUuid) {
                                    opts.process.flow.children.forEach(function (node, index) {
                                        if (node.nodeType !== "commentbox" && node.eid === nodeUuid) {
                                            node.eid = newNodeUuid;
                                            node.nodeUuid = newNodeUuid;
                                            node.oldEid = nodeUuid;
                                            node.signIsChange = true;
                                        }
                                    })
                                };

                                //遍历子节点，并修改其eid
                                opts.process.flow.children.map(function (c) {
                                    var oldAlgId = c.signIsChange == true ? c.oldEid : c.eid;
                                    var newAlgId = c.signIsChange == true ? c.eid : TempoUtils.uuid();

                                    delete c.signIsChange;
                                    delete c.oldEid;

                                    //当是节点注释时，则先替换源节点的eid，再替换当前节点的nodeUuid
                                    if (c.nodeType == "commentbox") {
                                        if (c.noteUuid) {
                                            c.noteUuid = c.noteUuid.replace(oldAlgId, newAlgId);
                                        }

                                        if (c.nodeUuid && c.parameters.comment_type != "process_comment") {
                                            var tempNewAlgId = TempoUtils.uuid();
                                            //修改开启注释节点的节点，修改该节点的uuid
                                            var nodeEid = c.nodeUuid.split("_")[0];
                                            c.parameters.comment_type = c.parameters.comment_type.replace(nodeEid, tempNewAlgId);
                                            changeCommentNodeEid(nodeEid, tempNewAlgId);
                                            c.nodeUuid = c.nodeUuid.replace(nodeEid, tempNewAlgId);
                                        }
                                    } else {
                                        if (c.nodeUuid) {
                                            c.nodeUuid = c.nodeUuid.replace(oldAlgId, newAlgId);
                                        }
                                    }

                                    if (c.eid != "END" && c.eid != "START" && c.eid != "") {
                                        c.eid = newAlgId;
                                        //遍历查找该节点相关连线，修改连线中id
                                        if (opts.process.flow.connections) {
                                            opts.process.flow.connections.map(function (e) {
                                                if (e.from_op == oldAlgId) {
                                                    e.from_op = newAlgId;
                                                }
                                                if (e.to_op == oldAlgId) {
                                                    e.to_op = newAlgId;
                                                }

                                            });
                                        }
                                    }
                                });
                            }
                        }
                    }
                    var offset = board.miningboard('getContainer').offset();
                    var left = evt.pageX - offset.left + node.x - minLeft;
                    var top = evt.pageY - offset.top + node.y - minTop;
                    left < 0 && (left = 0);
                    top < 0 && (top = 0);
                    opts.style.left = left;
                    opts.style.top = top;
                    Eventbus.trigger("mining_board_change.mine");


                    //文件上传节点，复制节点时，文件也进行复制，并替换新节点文件存储位置  和批量文件上传节点复制
                    if (node.data.nodeType == "readdatabank" || node.data.nodeType == "readdatabankbatch" ||
                        node.data.nodeType == "readsignalfile" || node.data.nodeType == "readfile") {
                        $.ajax({
                            url: contextPath + '/api/ai/node/readdatabank/changeFilePath',
                            data: {
                                eid: opts.eid,
                                fileId: opts.parameters.fileId,
                                themeId: opts.parameters.themeId,
                                flowId: opts.parameters.flowId,
                                newFlowId: window.analyseStatus.getMainId() || opts.parameters.flowId
                            },
                            async: false,
                            type: 'post',
                            success: function (datas) {
                                if (node.data.nodeType == "readsignalfile" && opts.parameters.filePath) {
                                    //修改保存的文件路径
                                    opts.parameters.filePath = opts.parameters.filePath
                                        .replace(opts.parameters.fileId, datas.fileId).replace(opts.parameters.flowId, datas.flowId);
                                }
                                if (datas.fileId && datas.flowId) {
                                    opts.parameters.fileId = datas.fileId;
                                    opts.parameters.flowId = datas.flowId;
                                }
                            }
                        });
                    }

                    //如果复制的是注释节点,需要进行特殊处理
                    if (node.data.nodeType == "commentbox") {
                        var flow = board.miningboard("getJson");
                        var comsflag = flow.comsflag;
                        if (!comsflag) {

                        }
                        var quandata = panel.flowpanel('getRootData');
                        var childNodes = quandata.flow.children;
                        //复制流程注释节点
                        if (node.data.parameters.comment_type == "process_comment") {
                            var num = 0;
                            //判断是否超过5个流程注释节点
                            if (childNodes && childNodes.length && childNodes.length > 0) {
                                for (var i = 0; i < childNodes.length; i++) {
                                    var childNodeData = childNodes[i];
                                    //先筛选是否是注释节点
                                    if (childNodeData.nodeType != "commentbox") {
                                        continue;
                                    }
                                    if (TempoUtils.equals(childNodeData.parameters.comment_type, "process_comment")) {
                                        num = num + 1;
                                    }
                                }
                                //面板的流程注释不能超过5个
                                /*if(num>=5){
                                    TempoUtils.showTip(TempoUtils.locale("commentbox.procomsnum"));
                                    return;
                                }*/
                            }
                            //获取当前面板注释节点最大层级
                            var maxZIndex = board.miningboard("getMineCoMaxZIndex");
                            //粘贴之后最大层级需要+1
                            board.miningboard("setMineCoMaxZIndex", maxZIndex + 1);
                            opts.style.zIndex = maxZIndex + 1;
                            //that.updateCoZIndexByValue(maxZIndex+1,eleme);
                            $(node).css("zIndex", maxZIndex + 1);
                        } else {

                        }
                    }
                    var nodeType = node.data.nodeType;
                    var container = board.miningboard('getContainer');
                    var plumbInstance = board.miningboard('getJspInstance');
                    try {
                        //处理文件输出端口，删除没有连线的多余端口
                        if ((nodeType == "writefile" || nodeType == "writefilebatch") && connectionList.length > 0) {
                            //输入端口
                            var inScope = opts.scope.inScope;
                            var outScope = opts.scope.outScope;
                            var nodeId = opts.eid;
                            //保存要保留的输入端口的code
                            var saveInScopeCodes = [];
                            for (var i = 0; i < connectionList.length; i++) {
                                var targetNoteUuid = connectionList[i][1].split("_")[0];
                                if (nodeId == targetNoteUuid) {
                                    saveInScopeCodes.push(connectionList[i][1].split("_")[2]);
                                }
                            }
                            //删除多余端口
                            for (var i = 0; i < inScope.length; i++) {
                                var inScopeCode = inScope[i].code;
                                if (saveInScopeCodes.indexOf(inScopeCode) == -1 && i < outScope.length) {
                                    inScope.splice(i, 1);
                                    outScope.splice(i, 1);
                                    i--;
                                }
                            }
                        } else if (nodeType == "multiply" && connectionList.length > 0) {
                            //处理多分支输出端口，删除没有连线的多余端口
                            var outScope = opts.scope.outScope;
                            var nodeId = opts.eid;
                            //保存要保留的输出端口的code
                            var saveInScopeCodes = [];
                            for (var i = 0; i < connectionList.length; i++) {
                                var sourceNoteUuid = connectionList[i][0].split("_")[0];
                                if (nodeId == sourceNoteUuid) {
                                    saveInScopeCodes.push(connectionList[i][0].split("_")[2]);
                                }
                            }
                            //删除多余输出端口（多分支不删除最后一个输出端口）
                            for (var i = 0; i < outScope.length - 1; i++) {
                                var inScopeCode = outScope[i].code;
                                if (saveInScopeCodes.indexOf(inScopeCode) == -1) {
                                    outScope.splice(i, 1);
                                    i--;
                                }
                            }
                        }
                    } catch (e) {
                        console.error(e);
                    }
                    var node = renderNode({left: left, top: top},
                        opts, container, plumbInstance);

                    if (nodeType == "commentbox" && !board.miningboard('getComsFlag')) {
                        node.hide();
                    }
                    //节点ID
                    var id = node.attr('id');
                    //节点数据
                    var data = $.extend({}, opts);
                    newNodeId.push({
                        "id": id,
                        "data": data,
                        "left": left,
                        "top": top
                    });
                });

                var jsPlumb = board.miningboard('getJspInstance');

                /**
                 * 粘贴节点重新绘制连线
                 * @param connectionList
                 */
                var drawConnections = function (connectionList, jsPlumb) {
                    if (connectionList.length) {
                        jsPlumb.batch(function () {
                            for (var i = 0; i < connectionList.length; i++) {
                                if (JSON.stringify(connectionList[i]).indexOf("_NOTE_note") === -1) {
                                    jsPlumb.connect({uuids: connectionList[i]});
                                } else {
                                    var sourceNodeUuid = connectionList[i][0];
                                    var targetNoteUuid = connectionList[i][1].split("_")[0];
                                    //在当前面板上获取节点dom元素
                                    var $targetNoteNode = board.find("#" + targetNoteUuid);
                                    var $sourceNoteNode = board.find("#" + sourceNodeUuid.split("_")[0]);
                                    //只有获取到连线来源节点才进行连线，否则不进行连线
                                    if ($sourceNoteNode.length > 0) {
                                        $targetNoteNode[$targetNoteNode.attr('_widgetname')]("connectComment", sourceNodeUuid);
                                    }
                                }
                            }
                        });
                        //防止锚点位置错误，重新绘制
                        jsPlumb.repaintEverything();
                    }
                };
                var newNodeIdTemp = TempoUtils.clone(newNodeId);
                //粘贴之后的撤销和重做
                var undoManager = analyseStatus.getUndoManager();
                undoManager.add({
                    undo: function () {
                        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
                        var boardId = analyseStatus.getMainId();
                        var panel = analyseStatus.getFlowPanel(boardId).panel;
                        board = panel.flowpanel('getBoard');
                        var jsPlumb = board.miningboard('getJspInstance');

                        console.log("回退批量粘贴的节点");
                        var newNodeIdTempUndo = TempoUtils.clone(newNodeIdTemp);
                        jsPlumb.batch(function () {
                            for (var i = 0; i < newNodeIdTempUndo.length; i++) {
                                var node = $('#' + parentId).find('#' + newNodeIdTempUndo[i].id);
                                var widgetName = node.attr('_widgetname');
                                if (node && widgetName) {
                                    if (widgetName == "minecommentnode") {
                                        node[widgetName]('remove', node);
                                    } else {
                                        node[widgetName]('remove');
                                    }
                                }
                            }
                        });
                        //防止锚点位置错误，重新绘制
                        jsPlumb.repaintEverything();
                        Eventbus.trigger("mining_board_change.mine");
                    },
                    redo: function () {
                        //var board = $('#' + parentId);
                        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
                        var boardId = analyseStatus.getMainId();
                        var panel = analyseStatus.getFlowPanel(boardId).panel;
                        board = panel.flowpanel('getBoard');
                        var jsPlumb = board.miningboard('getJspInstance');

                        var newNodeIdTempRedo = TempoUtils.clone(newNodeIdTemp);
                        jsPlumb.batch(function () {
                            for (var i = 0; i < newNodeIdTempRedo.length; i++) {
                                var nowNewNode = newNodeIdTempRedo[i];
                                renderNode({left: nowNewNode.left, top: nowNewNode.top}, nowNewNode.data,
                                    board.miningboard('getContainer'),
                                    board.miningboard('getJspInstance'));
                            }
                        });
                        //添加连线
                        drawConnections(connectionList, jsPlumb);
                        //防止锚点位置错误，重新绘制
                        jsPlumb.repaintEverything();
                        Eventbus.trigger("mining_board_change.mine");
                    }
                });
                Eventbus.trigger('enableUndoRedoButton.mineToolbar');

                //粘贴后面板不渲染问题！
                if (board != null) {

                    //渲染节点复制后的连线
                    drawConnections(connectionList, jsPlumb);

                    board.miningboard("updateSize");
                }
            }
            progressbar.tempoprogressbar("destroy");
        }, 100);
    }

    /**
     * 添加流程注释
     */
    var addProComs = function () {
        var num = 0;
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var boardId = analyseStatus.getMainId();
        var panel = analyseStatus.getFlowPanel(boardId).panel;
        var board = $('#' + parentId);
        //面板所有节点的数据
        var quandata = board.miningboard("getJson");
        var childNodes = quandata.children;
        if (childNodes && childNodes.length && childNodes.length > 0) {
            for (var i = 0; i < childNodes.length; i++) {
                var childNodeData = childNodes[i];
                //先筛选是否是注释节点
                if (childNodeData.nodeType != "commentbox") {
                    continue;
                }
                if (TempoUtils.equals(childNodeData.parameters.comment_type, "process_comment")) {
                    num = num + 1;
                }
            }
            //面板的流程注释不能超过5个
            /*if(num>=5){
				TempoUtils.showTip(TempoUtils.locale("commentbox.procomsnum"));
				return;
			}*/
        }
        var that = this;
        var opts = {};
        var container = board.miningboard('getContainer');
        var jspInstance = board.miningboard('getJspInstance');
        var offset = container.offset();
        opts = {
            category: "data_input",
            type: "dm_data",
            nodeType: "commentbox",
            id: "",
            parameters: {
                contents: "",
                //此为流程注释
                comment_type: "process_comment"
            },
            style: {
                //注释节点层级
                zIndex: num + 1,
                left: 8 * num + 40,
                top: 8 * num + 20,
                position: "absolute"
            }
        };
        var div = $("<div/>").css(opts.style);
        var config = window[opts.type][opts.nodeType];
        var rendernode = config.renderNode;
        rendernode = rendernode && rendernode != "" ? rendernode : "minecommentnode";
        container.append(div);
        var canBeEdit = true;
        var draggable = true;
        if (window.apiPreview) {
            canBeEdit = false;
            draggable = false;
        }
        var node = div[rendernode]($.extend(true, {}, {
            showHandle: false,
            canBeEdit: canBeEdit,
            draggable: draggable,
            data: opts,
            loadProp: true,
            containment: container,
            jspInstance: jspInstance,
            board: container.parent(),
        }));
        console.log(opts);
        board.miningboard('setMineCoMaxZIndex', num + 1);
        var id = node.attr('id');
        var undoManager = analyseStatus.getUndoManager();
        undoManager.add({
            undo: function () {
                console.log("回退添加流程注释");
                var node = $('#' + id);
                var widgetName = node.attr('_widgetname');
                if (node && widgetName) {
                    node[widgetName]('remove', node);
                }
                //去掉流程注释时要记得最大层级-1
                var maxzIndex = board.miningboard('getMineCoMaxZIndex');
                board.miningboard('setMineCoMaxZIndex', maxzIndex - 1);
            },
            redo: function () {
                //var node = $('#' + id);
                //增添流程注释时要记得最大层级+1
                var maxzIndex = board.miningboard('getMineCoMaxZIndex');
                board.miningboard('setMineCoMaxZIndex', maxzIndex + 1);
                node = renderNode(opts.style, opts,
                    board.miningboard('getContainer'),
                    board.miningboard('getJspInstance'));
                //去掉其他节点的选中状态
                board.find(".tempo-basenode").each(function (i, it) {
                    var item = $(it);
                    var widget = item.attr("_widgetName");
                    item[widget]('unselectNode');
                })
                //增添流程注释并使其处于编辑状态
                node[node.attr('_widgetname')]('editComNode');
            }
        });
        Eventbus.trigger('enableUndoRedoButton.mineToolbar')
        Eventbus.trigger("mining_board_change.mine");
        //去掉其他节点的选中状态
        board.find(".tempo-basenode").each(function (i, it) {
            var item = $(it);
            var widget = item.attr("_widgetName");
            item[widget]('unselectNode');
        })
        node[node.attr('_widgetname')]('editComNode');
        return node;
    }

    /**
     * 显示或隐藏全部注释
     */
    var AllComs = function (evt, ui) {
        var board = $('#' + parentId);
        var flow = board.miningboard("getJson");
        var comsflag = flow.comsflag;
        //获取到所有的注释框对象
        var div = panel.find(".tempo-minecommentnode.tempo-miningnode");
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var undoManager = analyseStatus.getUndoManager();
        var jsPlumb = board.miningboard('getJspInstance');
        if (comsflag) {
            //此处是隐藏所有注释框的操作,text应改为显示
            board.miningboard('setComsFlag', false);
            $.each(div, function () {
                var comnode = $(this);
                var data = comnode[comnode.attr("_widgetname")]("getData");
                if (data.parameters.comment_type.substr(0, 7) != "process") {
                    comnode[comnode.attr("_widgetname")]("removeconnectComment", comnode);
                }
            });
            div.hide();
            undoManager.add({
                undo: function () {
                    console.log("回退隐藏全部注释");
                    div.show();
                    board.miningboard('setComsFlag', true);
                    board.miningboard('addconnectComment');
                    jsPlumb.repaintEverything();
                    Eventbus.trigger("mining_board_change.mine");
                },
                redo: function () {
                    board.miningboard('setComsFlag', false);
                    //新增的注释节点可能获取不到，重新获取一下
                    div = panel.find(".tempo-minecommentnode.tempo-miningnode");
                    $.each(div, function () {
                        var comnode = $(this);
                        var data = comnode[comnode.attr("_widgetname")]("getData");
                        if (data.parameters.comment_type.substr(0, 7) != "process") {
                            comnode[comnode.attr("_widgetname")]("removeconnectComment", comnode);
                        }
                    });
                    div.hide();
                    Eventbus.trigger("mining_board_change.mine");
                }
            });
            Eventbus.trigger('enableUndoRedoButton.mineToolbar');
            Eventbus.trigger("mining_board_change.mine");
        } else {
            //此处是显示所有注释框的操作，text应改为隐藏
            div.show();
            board.miningboard('setComsFlag', true);
            board.miningboard('addconnectComment');
            jsPlumb.repaintEverything();
            undoManager.add({
                undo: function () {
                    console.log("回退显示全部注释");
                    board.miningboard('setComsFlag', false);
                    div = panel.find(".tempo-minecommentnode.tempo-miningnode");
                    $.each(div, function () {
                        var comnode = $(this);
                        var data = comnode[comnode.attr("_widgetname")]("getData");
                        if (data.parameters.comment_type.substr(0, 7) != "process") {
                            comnode[comnode.attr("_widgetname")]("removeconnectComment", comnode);
                        }
                    });
                    div.hide();
                    Eventbus.trigger("mining_board_change.mine");
                },
                redo: function () {
                    //新增的注释节点可能获取不到，重新获取一下
                    div = panel.find(".tempo-minecommentnode.tempo-miningnode");
                    div.show();
                    board.miningboard('setComsFlag', true);
                    board.miningboard('addconnectComment');
                    jsPlumb.repaintEverything();
                    Eventbus.trigger("mining_board_change.mine");
                }
            });
            Eventbus.trigger('enableUndoRedoButton.mineToolbar');
            Eventbus.trigger("mining_board_change.mine");
        }
    }

    var importNode = function (id, data) {
        try {
            var json = typeof data == "string" ? JSON.parse(data) : data || {};
            console.log(json);
            var flow = json.flow || {};
            var children = flow.children || [];
            var connections = flow.connections || [];
            // 获取流程参数
            var flowParams = flow.flowParams || [];
            var map = {};
            var board = $('#md-' + id);
            //先将old节点id和new节点id对应关系保存下来，防止节点注释没有节点加载快，导致保存的数据是undefiend的问题（修改59367bug）
            children.forEach(function (e) {
                if (e.nodeType == 'END') return;
                map[e.eid] = TempoUtils.uuid();
            });
            //修改节点ID和连线，防止节点冲突
            children.forEach(function (e) {
                if (e.nodeType == 'END') return;
                e.eid = map[e.eid];
                var parameters = e.parameters;
                if (e.nodeType != "matlab") {
                    if (parameters.iscachesucess !== undefined) {
                        delete parameters.iscachesucess;
                    }
                }
                if (e.nodeType != "matlab") {
                    if (parameters.cachestatus !== undefined) {
                        delete parameters.cachestatus;
                    }
                }

                var blacklist = ['readdatabank'];
                if (blacklist.indexOf(e.nodeType) > -1) {
                    //e.parameters = {};
                }
                e.status = undefined;
                //判断是否是节点注释
                if (e.noteUuid && e.noteUuid != "") {
                    //获取到对应节点的旧的id
                    var oldid = e.nodeUuid.split('_NOTE_')[0];
                    //通过map和旧id得到新的id
                    e.nodeUuid = map[oldid] + '_NOTE_node';
                }
                Eventbus.trigger("mining_board_change.mine");
                renderNode(e.style, e, board.miningboard('getContainer'),
                    board.miningboard('getJspInstance'));
            });
            connections = connections.map(function (e) {
                if (map[e.from_op]) e.from_op = map[e.from_op];
                if (map[e.to_op]) e.to_op = map[e.to_op];
                return e;
            });
            if (connections.length) {
                board.miningboard('connect', connections);
            }
            board.miningboard('addconnectComment');
            var panel = $('#fc-' + id);
            if (json.logger && json.logger.message) {
                var logger = panel.flowpanel('getLogger');
                logger.flowlogger('showLog', json.logger.message);
            }
            // 更新画布大小，如超出画布，则出现滚动条
            board.miningboard('updateSize');
            if (masterType && masterType.startsWith('merit-')) {
                var blacklist = ['readhive', 'readhbase', 'readhdfs', 'tensorflow', 'writehive', 'writehbase', 'writehdfs'];
                var eles = children.filter(function (e) {
                    return e && blacklist.indexOf(e.nodeType) > -1;
                });
                if (eles.length > 0) {
                    $("<div/>").alert({msg: TempoUtils.locale('mine.import_unknow_node')});
                }
            }
            var isOPenHadoop = getOpenHadoop();
            //导入非k8s流程下的节点 前端弹框提示
            if (masterType && (masterType == "k8s-cluster" || masterType == "k8s-local") && !isOPenHadoop) {
                var blacklist = ['readdatabankbatch', 'pyspark', 'readsync', 'syncoutput', 'readkafka', 'writekafka', 'readhive', 'readhbase', 'readhdfs', 'tensorflow', 'writehive', 'writehbase', 'writehdfs', 'matlab', "ambiguityfunction", "datatosignal", "exmodeldecompose", "fouriertrans", "hilberthuangtransform", "hilberttransform",
                    "orderenvelope", "readiotdbsignal", "readsignal1", "readsignalfile", "signaladaptivefilter", "signalamplitudespectrum"
                    , "signalbutterworth", "signalchangepointdetection", "signalcrosspower", "signalfeatureextraction1", "signalfilters1", "signalholographic2d",
                    "signalinversefourier", "signalphasespectrum", "signalprocessingextension", "signalresampling", "signalsconversion", "signalselfpower", "signalseqarate",
                    "signalsimilarity", "signaltodata", "signalwienerfiltering", "signalwignerville", "singalfeartureextact", "vmdsignal", "wavelettransform", "writeiotdbsignal", "writesignalfile", "pythonparallelization"];

                var eles = children.filter(function (e) {
                    return e && blacklist.indexOf(e.nodeType) > -1;
                });
                if (eles.length > 0) {
                    $("<div/>").alert({msg: TempoUtils.locale('mine.import_unknow_node')});
                }
            }
            if (masterType && (masterType == "k8s-cluster" || masterType == "k8s-local") && isOPenHadoop) {
                var blacklist = ['readdatabankbatch', 'readsync', 'syncoutput', 'pyspark', 'readkafka', 'writekafka', 'matlab', 'tensorflow', "ambiguityfunction", "datatosignal", "exmodeldecompose", "fouriertrans", "hilberthuangtransform", "hilberttransform",
                    "orderenvelope", "readiotdbsignal", "readsignal1", "readsignalfile", "signaladaptivefilter", "signalamplitudespectrum"
                    , "signalbutterworth", "signalchangepointdetection", "signalcrosspower", "signalfeatureextraction1", "signalfilters1", "signalholographic2d",
                    "signalinversefourier", "signalphasespectrum", "signalprocessingextension", "signalresampling", "signalsconversion", "signalselfpower", "signalseqarate",
                    "signalsimilarity", "signaltodata", "signalwienerfiltering", "signalwignerville", "singalfeartureextact", "vmdsignal", "wavelettransform", "writeiotdbsignal", "writesignalfile", "pythonparallelization"];
                var eles = children.filter(function (e) {
                    return e && blacklist.indexOf(e.nodeType) > -1;
                });
                if (eles.length > 0) {
                    $("<div/>").alert({msg: TempoUtils.locale('mine.import_unknow_node')});
                }
            }
            // 回显流程参数
            panel.flowpanel('updateFlowParams', flowParams);
            //设置流程参数
            panel.flowpanel("getBoard").miningboard('setFlowParams', flowParams);
            //设置是否是导入流程标识
            if (data && data.importNotExecuted) {
                panel.flowpanel('updateImportNotExecuted', data.importNotExecuted);
            }
            //导入时前端保存importMLeapExeId供后端直接导入就下载使用MLeap模型文件
            if (data && data.importMLeapExeId) {
                panel.flowpanel('updateImportMLeapExeId', data.importMLeapExeId);
            }
        } catch (e) {

        }
    }

    var getOpenHadoop = function () {
        var openHadoop = false;
        $.ajax({
            url: contextPath + '/api/ai/mine/getOpenHadoop',
            type: 'get',
            async: false,
            success: function (result) {
                openHadoop = result;
            }
        })
        return openHadoop;
    }
    var clearEventBubble = function (evt) {
        if (evt.stopPropagation)
            evt.stopPropagation();
        else
            evt.cancelBubble = true;
        if (evt.preventDefault)
            evt.preventDefault();
        else
            evt.returnValue = false;
    }

    /**
     * 批量删除节点
     */
    var batchDeleteNode = function (evt, ui) {
        var analyseStatus = Eventbus.triggerHandler("getAnalyseStatus")[0];
        var boardId = analyseStatus.getMainId();
        var panel = analyseStatus.getFlowPanel(boardId).panel;
        var board = panel.flowpanel('getBoard');
        var keyDownEvent = {
            originalEvent: {
                keyCode: 46
            }
        };
        board[board.attr('_widgetname')]("removeSelect", keyDownEvent);
    }


    var graphDialog = function (id, linkEl) {
        var height = window.innerHeight - 60;
        var url = contextPath + '/multiline/config/property';
        var dialog = $('<div id="tempo-multiline-dialog">').appendTo($('body'));
        var paramDialog = dialog.dialog({
            title: 'IoTDB输出-图表分析',
            autoOpen: true,
            width: "100%",
            height: height,
            modal: true,
            init: function () {

            },
            resizable: false,
            open: function () {
            },
            close: function () {
                dialog.dialog("destroy").remove();
            }
        })

        var data = linkEl[linkEl.attr("_widgetName")]("getData");
        var argsData = data;
        argsData.type = "minechart";
        var url = contextPath + '/api/ai/mine/' + 'multiline/config/property';
        $m.loadHtml(url, dialog, 'multiline', {data: argsData, dialog: paramDialog, source: linkEl});
    }

    /**
     * 构建一键转自定义算子模型
     * @param paramters
     */
    var buildExtendNodeTransData = function (parameters) {
        var designModel = parameters.tempoAICustomAlg.designModel;
        // designModel.lang = "Python";

        // 判断python的N端口是否被连接
        if (parameters.tempoAICustomAlg.isConnectModel) {
            TempoUtils.showTip(TempoUtils.locale("mine.pythonConnectModelTip"));
            return false;
        }

        // 构建算法代码文件file文件
        var scriptArray = [];
        var bit = parameters.bit;
        for (var i = 0; i < parameters.script.length; i++) {
            var line = parameters.script[i][0];
            // 判断代码中是否使用了python模型，判断代码中是否使用了流程参数
            if (line.length != 0) {
                // var lineTmp = line.replaceAll(" ","");
                if (line.indexOf("setModelInsight") != -1) {
                    TempoUtils.showTip(TempoUtils.locale("mine.pythonCodeHaveModelInsightTip").replace("${row}", i + 1));
                    return false;
                }
                if (line.indexOf("getFlowParameter") != -1 || /\$\{.*\}/.test(line)) {
                    TempoUtils.showTip(TempoUtils.locale("mine.pythonFlowParamTip").replace("${row}", i + 1));
                    return false;
                }
            }
            scriptArray.push(line.substr(bit) + "\n");
        }
        designModel.scriptArray = scriptArray;

        // 将节点id添加进去
        designModel.nodeId = TempoUtils.uuid();
        // 代码转自定义算法-构建端口信息
        buildCustomAlgScope(designModel.scopes);
        return true;
    };

    /**
     * 代码转自定义算法-构建端口信息
     * @param scopes 端口信息，包括inScope和outScope
     * @param inScopeNum 输入端口保留几个，无效
     * @param outScope 输出端口保留几个，无效
     */
    function buildCustomAlgScope(scopes) {
        // 以全部端口数-1，至少保留一个端口
        // scopes.inScope = scopes.inScope.splice(0, inScopeNum);
        // scopes.outScope = scopes.outScope.splice(0, outScopeNum);
        // 构建inScope信息
        var inScopeLen = scopes.inScope.length;
        if (inScopeLen > 1) scopes.inScope = scopes.inScope.splice(0, inScopeLen - 1);
        var inScopeTmp = [];
        for (var i = 0; i < inScopeLen - 1; i++) {
            if (scopes.inScope[i].code == "object") {
                continue;
            }
            var inScopeOneTmp = {
                name: scopes.inScope[i].name,
                code: scopes.inScope[i].code,
                dataName: '',
                dataId: '',
                data: ""
            };
            inScopeTmp.push(inScopeOneTmp);
        }
        scopes.inScope = inScopeTmp;
        // 构建outScope信息
        var outScopeLen = scopes.outScope.length;
        var outScopeTmp = [];
        for (var i = 0; i < outScopeLen; i++) {
            if (scopes.outScope[i].code == "object") {
                continue;
            }
            var outScopeOneTmp = {
                name: scopes.outScope[i].name,
                code: scopes.outScope[i].code,
                metadata: {
                    type: "default",
                    outPorts: [],
                    fields: [],
                    code: "",
                }
            };
            outScopeTmp.push(outScopeOneTmp);
        }
        if (outScopeTmp.length > 1) {
            outScopeTmp.splice(outScopeTmp.length - 1, 1);
        }
        scopes.outScope = outScopeTmp;
    }

    /**
     * 构造node信息
     * @param nodeInfo 需要由node的id、name信息和流程的flowid和应用的themeid
     */
    var buildCustomAlgNodeInfo = function (nodeInfo) {
        // 获取流程信息
        $.ajax({
            url: contextPath + "/api/ai/resource/id-and-name",
            type: 'post',
            dataType: 'json',
            data: {
                id: nodeInfo.flowId
            },
            success: function (rs) {
                if (rs && rs.success && rs.data) {
                    nodeInfo.flowName = rs.data.flowName;
                    nodeInfo.themeName = rs.data.themeName;
                    nodeInfo.workspaceId = rs.data.workSpaceId;
                    nodeInfo.workspaceName = rs.data.workspaceName;
                } else {
                    console.log("获取空间、应用和流程信息失败", rs);
                }
            },
            error: function (e) {
                console.log("获取空间、应用和流程信息失败", e);
            }
        });
    };

    /**
     * 发布自定义算法提交成功后的提示事件
     * @param algName 算子名称
     */
    var commitTip = function (message) {
        TempoUtils.showTip(message);
    };

    /**
     * 发布为自定义算法
     * @param e 右键点击事件
     * @param ui contextmenu中的点击的数据
     */
    var publishCustomAlg = function (e, ui) {
        //构建扩展编程转换自定义算子数据
        var targetNodeData = $(ui.linkEl)[$(ui.linkEl).attr("_widgetName")]("getData");

        //弹出一键转自定义算法的dialog框
        //向body中插入一个div，用于渲染弹框
        if ($("#tempo-ai-publish-custom-alg").length > 0) {
            //如果存在该div，则清空
            $("#tempo-ai-publish-custom-alg").remove();
        }
        $("<div id='tempo-ai-publish-custom-alg'/>").appendTo($('body'));

        // 将parameters克隆一份，防止发布中的修改对其产生影响
        var nodeParametersTmp = TempoUtils.clone(targetNodeData.parameters);
        // 构建自定义算法模型
        if (!buildExtendNodeTransData(nodeParametersTmp)) return false;
        // 构建node信息，空间，应用，流程，节点
        var nodeInfo = {
            // 这个可能是假的
            nodeId: targetNodeData.eid,
            nodeName: targetNodeData.alias,
            flowId: flowId,
        };
        // 构建自定义算法所用的模型
        buildCustomAlgNodeInfo(nodeInfo);
        // 构建代码转自定义对象
        window.TempoAICustomAlg = {};
        // 存入模型-对接党哲的自定义算法
        window.TempoAICustomAlg.designModel = nodeParametersTmp.tempoAICustomAlg.designModel;
        window.TempoAICustomAlg.option = "transformation";
        var fileNameUuid = TempoUtils.uuid();
        // 创建算法文件
        if (typeof File == "function") {
            window.TempoAICustomAlg.file = new File(nodeParametersTmp.tempoAICustomAlg.designModel.scriptArray, fileNameUuid + ".py");
        } else if (typeof Blob == "function") {
            var codeScriptTmp = new Blob(nodeParametersTmp.tempoAICustomAlg.designModel.scriptArray, {type: "text/plan"});
            codeScriptTmp.name = fileNameUuid + ".py";
            codeScriptTmp.filename = fileNameUuid + ".py";
            codeScriptTmp.lastModifiedDate = new Date();
            codeScriptTmp.lastModified = codeScriptTmp.lastModified + codeScriptTmp.lastModifiedDate;
            codeScriptTmp.originalFilename = fileNameUuid + ".py";
            window.TempoAICustomAlg.file = codeScriptTmp;
        }
        // else if (window.MSBlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder) {
        //     var codeScriptTmp = new MSBlobBuilder();
        //     codeScriptTmp.append(nodeParametersTmp.tempoAICustomAlg.designModel.scriptArray);
        //     codeScriptTmp.name = fileNameUuid + ".py";
        //     codeScriptTmp.filename = fileNameUuid + ".py";
        //     codeScriptTmp.lastModifiedDate = new Date();
        //     codeScriptTmp.lastModified = codeScriptTmp.lastModified + codeScriptTmp.lastModifiedDate;
        //     codeScriptTmp.originalFilename = fileNameUuid + ".py";
        //     window.TempoAICustomAlg.file = codeScriptTmp;
        // }
        // 保存文件名
        window.TempoAICustomAlg.designModel.fileName = fileNameUuid + ".py";
        // 保存入口文件
        window.TempoAICustomAlg.designModel.entryFunction = fileNameUuid;
        window.TempoAICustomAlg.nodeInfo = nodeInfo;
        // 提交成功后的弹框事件
        window.TempoAICustomAlg.commitTip = commitTip;
        // 删除designModel.scriptArray
        delete nodeParametersTmp.tempoAICustomAlg.designModel.scriptArray;

        //使用httpVueLoader来运行vue代码
        Vue.use(httpVueLoader);
        new Vue({
            template: ' \
                <div id="tempo-ai-publish-custom-alg"> \
                    <el-drawer \
                        :title="publishCusAlgDialogConfig.title" \
                        :visible.sync="publishCusAlgDialogConfig.dialogVisible" \
                        :close-on-press-escape="false" \
                        :destroy-on-close="true" \
                        direction="btt" \
                        size="calc(100% - 36px)" \
                        custom-class="demo-drawer" \
                        ref="drawer" \
                    > \
                        <div class="demo-drawer__content" style="height: 100%;"> \
                            <iframe \
                                :src="publishCusAlgDialogConfig.uploadUrl" \
                                frameborder="0" \
                                style="height: calc(100%); width: 100%; overflow: auto;"> \
                            </iframe> \
                        </div> \
                    </el-drawer> \
                </div> \
            ',
            data: function () {
                return {
                    publishCusAlgDialogConfig: {
                        title: TempoUtils.locale("mine.publish_custom_alg"),
                        dialogVisible: true,
                        next: TempoUtils.locale("mine.publish-dialog-next"),
                        cancle: TempoUtils.locale("mine.publish-dialog-cancel"),
                        test: TempoUtils.locale("mine.test"),
                        commit: TempoUtils.locale("mine.tijiao"),
                        // 步骤标识，与其他页面同步
                        step: 0,
                        //一键转自定义算子的上传页面
                        uploadUrl: "/tempo-ai-web-design/algorithm/publish.html",
                        testloading: false,
                        // 测试成功
                        testStatus: false
                    }
                }
            },
            methods: {
                /**
                 * 下一步
                 */
                next: function () {
                    var publishThis = window.parent.TempoAICustomAlg.$publishThis;
                    publishThis.$options.methods.next.call(publishThis);
                    this.publishCusAlgDialogConfig.testloading = publishThis.testloading;
                },
                /**
                 * 上一步
                 */
                last: function () {
                    var publishThis = window.parent.TempoAICustomAlg.$publishThis;
                    publishThis.$options.methods.last.call(publishThis);
                    this.publishCusAlgDialogConfig.testloading = publishThis.testloading;
                },
                /**
                 * 测试
                 */
                test: function () {
                    var publishThis = window.parent.TempoAICustomAlg.$publishThis;
                    publishThis.$options.methods.test.call(publishThis);
                    this.publishCusAlgDialogConfig.testloading = publishThis.testloading;
                },
                /**
                 * 保存
                 */
                save: function () {
                    var publishThis = window.parent.TempoAICustomAlg.$publishThis;
                    publishThis.$options.methods.save.call(publishThis);
                },
                /**
                 * 修改测试状态
                 * @param status 测试状态
                 */
                changeTestStatus: function (status) {
                    this.publishCusAlgDialogConfig.testloading = false;
                    this.publishCusAlgDialogConfig.testStatus = status;

                },
                /**
                 * 同步步骤条
                 * @param step 步骤条的步骤数
                 */
                changeStep: function (step) {
                    this.publishCusAlgDialogConfig.step = step;
                },
                /**
                 * 关闭抽屉
                 */
                handleClose: function () {
                    this.publishCusAlgDialogConfig.dialogVisible = false;
                }
            },
            mounted: function () {
                window.parent.TempoAICustomAlg.$parentThis = this;
                var dialog = $("#tempo-ai-publish-custom-alg");
                dialog.find(".el-drawer__header").css("margin-bottom", "0px").css("padding", "10px 10px");
                dialog.find(".el-drawer__header").css("line-height", "24px").css("color", "#333");
                dialog.find(".el-drawer__header span[role='heading']").css("font-size", "14px");
                dialog.find(".el-drawer__header .el-drawer__close-btn .el-dialog__close").css("position", "absolute").css("right", "10px").css("top", "15px");
            }
        }).$mount('#tempo-ai-publish-custom-alg');
    };

    /**
     * 算子列表
     * @param e 右键点击事件
     * @param ui contextmenu中的点击的数据
     */
    var customAlgList = function (e, ui) {
        //弹出一键转自定义算法的dialog框
        //向body中插入一个div，用于渲染弹框
        if ($("#tempo-ai-code-transfrom-alg-list").length > 0) {
            //如果存在该div，则清空
            $("#tempo-ai-code-transfrom-alg-list").remove();
        }
        $("<div id='tempo-ai-code-transfrom-alg-list'/>").appendTo($('body'));

        // 准备window数据，算子列表所用参数全部存储在customAlgList里
        window.customAlgList = {};

        //使用httpVueLoader来运行vue代码
        Vue.use(httpVueLoader);
        new Vue({
            template: ' \
                <div id="tempo-ai-code-transfrom-alg-list"> \
                    <el-drawer \
                        :title="customAlgList.title" \
                        :visible.sync="customAlgList.dialogVisible" \
                        :close-on-press-escape="false" \
                        :destroy-on-close="true" \
                        direction="btt" \
                        size="calc(100% - 36px)" \
                        custom-class="demo-drawer" \
                        ref="drawer" \
                    > \
                        <div class="demo-drawer__content" style="height: 100%;"> \
                            <iframe \
                                :src="customAlgList.uploadUrl" \
                                frameborder="0" \
                                style="height: 100%; width: 100%; overflow: auto;"> \
                            </iframe> \
                        </div> \
                    </el-drawer> \
                </div> \
            ',
            data: function () {
                return {
                    customAlgList: {
                        title: TempoUtils.locale("mine.customAlgListTitle"),
                        dialogVisible: true,
                        // 算子列表页面
                        uploadUrl: "/tempo-ai-web-design/algorithm/list.html",
                    }
                }
            },
            methods: {},
            mounted: function () {
                window.parent.customAlgList.$parentThis = this;
                var dialog = $("#tempo-ai-code-transfrom-alg-list");
                dialog.find(".el-drawer__header").css("margin-bottom", "0px").css("padding", "10px 10px");
                dialog.find(".el-drawer__header").css("line-height", "24px").css("color", "#333");
                dialog.find(".el-drawer__header span[role='heading']").css("font-size", "14px");
                dialog.find(".el-drawer__header .el-drawer__close-btn .el-icon-close")[0].content = "\e6db";
                dialog.find(".el-drawer__header .el-drawer__close-btn .el-dialog__close").css("position", "absolute").css("right", "10px").css("top", "15px");
            }
        }).$mount('#tempo-ai-code-transfrom-alg-list');
    };

    !function () {
        loadAnalyseFlow();
        Eventbus.one('importNode.mine', importNode);
        Eventbus.one('mineSave.mine', mineSave);
        Eventbus.one('renderNode.mine', renderNode);
        Eventbus.one('renderBoard.mine', renderBoard);
    }();
});